<commit_before>/******************************************************************************
 *
 * Project:  laszip - http://liblas.org -
 * Purpose:
 * Author:   Martin Isenburg
 *           martin.isenburg at gmail.com
 *
 ******************************************************************************
 * Copyright (c) 2009, Martin Isenburg
 *
 * This is free software; you can redistribute and/or modify it under
 * the terms of the GNU Lesser General Licence as published
 * by the Free Software Foundation.
 *
 * See the COPYING file for more information.
 *
 ****************************************************************************/

/*
===============================================================================

  FILE:  rangeencoder.cpp

  CONTENTS:

    see header file

  PROGRAMMERS:

    martin isenburg@cs.unc.edu

  COPYRIGHT:

    copyright (C) 2003 martin isenburg (isenburg@cs.unc.edu)

    This software 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.

  CHANGE HISTORY:

    see header file

===============================================================================
*/
#include "rangeencoder.h"

#include <stdlib.h>
#include <string.h>
#include <assert.h>

RangeEncoder::RangeEncoder(FILE* fp, bool store_chars)
{
  if (fp)
  {
    this->fp = fp;
    chars = 0;
    number_chars = 0;
  }
  else
  {
    this->fp = 0;
    if (store_chars)
    {
      chars = (unsigned char*)malloc(sizeof(unsigned char)*1000);
      number_chars = 0;
      allocated_chars = 1000;
    }
    else
    {
      chars = 0;
      number_chars = 0;
    }
  }
  low = 0;                /* Full code range */
  range = TOP_VALUE;
  /* this buffer is written as first byte in the datastream (header,...) */
  buffer = HEADERBYTE;
  help = 0;               /* No bytes to follow */
  bytecount = 0;
}

void RangeEncoder::encode(RangeModel* rm, unsigned int sym)
{
  unsigned int syfreq;
  unsigned int ltfreq;
  unsigned int r, tmp;
  unsigned int lg_totf = rm->lg_totf;

  assert(sym >= 0 && sym < (unsigned int)rm->n);

  rm->getfreq(sym,&syfreq,&ltfreq);

  normalize();
  r = range >> lg_totf;
  tmp = r * ltfreq;
  low += tmp;
#ifdef EXTRAFAST
  range = r * syfreq;
#else
  if ((ltfreq+syfreq) >> lg_totf)
  {
    range -= tmp;
  }
  else
  {
    range = r * syfreq;
  }
#endif

  rm->update(sym);
}

void RangeEncoder::writeBits(unsigned int bits, unsigned int sym)
{
  assert(bits && (sym < (1u<<bits)));

  if (bits > 21) // 22 bits
  {
    writeShort(sym&65535);
    sym = sym >> 16;
    bits = bits - 16;
  }

  unsigned int r, tmp;
  normalize();
  r = range >> bits;
  tmp = r * sym;
  low += tmp;
#ifdef EXTRAFAST
  range = r;
#else
  if ((sym+1) >> bits)
  {
    range -= tmp;
  }
  else
  {
    range = r;
  }
#endif
}

void RangeEncoder::writeRange(unsigned int range, unsigned int sym)
{
  assert(range && (sym < range));

  if (range > 4194303) // 22 bits
  {
    writeShort(sym&65535);
    sym = sym >> 16;
    range = range >> 16;
    range++;
  }
  unsigned int r, tmp;
  normalize();
  r = this->range / range;
  tmp = r * sym;
  low += tmp;
#ifdef EXTRAFAST
  this->range = r;
#else
  if (sym+1 < range)
  {
    this->range = r;
  }
  else
  {
    this->range -= tmp;
  }
#endif
}

void RangeEncoder::writeRange64(U64 range, U64 sym)
{
  assert(sym < range);
  if (range > 4294967295) // 32 bits
  {
    writeInt((unsigned int)(sym&4294967295));
    sym = sym >> 32;
    range = range >> 32;
    range++;
  }
  writeRange((unsigned int)range, (unsigned int)sym);
}

void RangeEncoder::writeByte(unsigned char c)
{
  unsigned int r, tmp;
  normalize();
  r = range >> 8;
  tmp = r * (unsigned int)(c);
  low += tmp;
#ifdef EXTRAFAST
  range = r;
#else
  if (((unsigned int)(c)+1) >> 8)
  {
    range -= tmp;
  }
  else
  {
    range = r;
  }
#endif
}

void RangeEncoder::writeShort(unsigned short s)
{
  unsigned int r, tmp;
  normalize();
  r = range >> 16;
  tmp = r * (unsigned int)(s);
  low += tmp;
#ifdef EXTRAFAST
  range = r;
#else
  if (((unsigned int)(s)+1) >> 16)
  {
    range -= tmp;
  }
  else
  {
    range = r;
  }
#endif
}

void RangeEncoder::writeInt(unsigned int i)
{
  writeShort((unsigned short)(i % 65536)); // lower 16 bits
  writeShort((unsigned short)(i / 65536)); // UPPER 16 bits
}

void RangeEncoder::writeInt64(U64 l)
{
  writeInt((unsigned int)(l % 4294967296)); // lower 32 bits
  writeInt((unsigned int)(l / 4294967296)); // UPPER 32 bits
}

void RangeEncoder::writeFloat(float f)
{
  writeInt(*((unsigned int*)(&f)));
}

void RangeEncoder::writeDouble(double d)
{
  writeInt64(*((U64*)(&d)));
}

/* I do the normalization before I need a defined state instead of */
/* after messing it up. This simplifies starting and ending.       */
inline void RangeEncoder::normalize()
{
  while(range <= BOTTOM_VALUE) /* do we need renormalisation?  */
  {
    if (low < (unsigned int)0xff<<SHIFT_BITS)  /* no carry possible --> output */
    {
      outbyte(buffer);
      for(; help; help--)
      {
        outbyte(0xff);
      }
      buffer = (unsigned char)(low >> SHIFT_BITS);
    }
    else if (low & TOP_VALUE) /* carry now, no future carry */
    {
      outbyte(buffer+1);
      for(; help; help--)
      {
        outbyte(0);
      }
      buffer = (unsigned char)(low >> SHIFT_BITS);
    }
    else                      /* passes on a potential carry */
    {
      help++;
    }
    range <<= 8;
    low = (low<<8) & (TOP_VALUE-1);
    bytecount++;
  }
}

/* Finish encoding                                           */
/* actually not that many bytes need to be output, but who   */
/* cares. I output them because decode will read them :)     */
/* the return value is the number of bytes written           */
unsigned int RangeEncoder::done()
{
  unsigned int tmp;
  normalize();     /* now we have a normalized state */
  bytecount += 5;
  if ((low & (BOTTOM_VALUE-1)) < ((bytecount&0xffffffL)>>1))
  {
    tmp = low >> SHIFT_BITS;
  }
  else
  {
    tmp = (low >> SHIFT_BITS) + 1;
  }
  if (tmp > 0xff) /* we have a carry */
  {
    outbyte(buffer+1);
    for(; help; help--)
    {
      outbyte(0);
    }
  }
  else  /* no carry */
  {
    outbyte(buffer);
    for(; help; help--)
    {
      outbyte(0xff);
    }
  }
  outbyte(tmp & 0xff);
  outbyte((bytecount>>16) & 0xff);
  outbyte((bytecount>>8) & 0xff);
  outbyte(bytecount & 0xff);
  return bytecount;
}

RangeEncoder::~RangeEncoder()
{
  if (chars)
  {
    free(chars);
  }
}

unsigned char* RangeEncoder::getChars()
{
  return chars;
}

int RangeEncoder::getNumberChars()
{
  return number_chars;
}

long RangeEncoder::getNumberBits()
{
  return bytecount*8;
}

int RangeEncoder::getNumberBytes()
{
  return bytecount;
}

inline void RangeEncoder::outbyte(unsigned int c)
{
  if (fp)
  {
    fputc(c, fp);
  }
  else
  {
    if (chars)
    {
      if (number_chars == allocated_chars)
      {
        unsigned char* newchars = (unsigned char*) malloc(sizeof(unsigned char)*allocated_chars*2);
        memcpy(newchars,chars,sizeof(unsigned char)*allocated_chars);
        free(chars);
        chars = newchars;
        allocated_chars = allocated_chars*2;
      }
      chars[number_chars++] = c;
    }
  }
}
<commit_msg>ull for constant<commit_after>/******************************************************************************
 *
 * Project:  laszip - http://liblas.org -
 * Purpose:
 * Author:   Martin Isenburg
 *           martin.isenburg at gmail.com
 *
 ******************************************************************************
 * Copyright (c) 2009, Martin Isenburg
 *
 * This is free software; you can redistribute and/or modify it under
 * the terms of the GNU Lesser General Licence as published
 * by the Free Software Foundation.
 *
 * See the COPYING file for more information.
 *
 ****************************************************************************/

/*
===============================================================================

  FILE:  rangeencoder.cpp

  CONTENTS:

    see header file

  PROGRAMMERS:

    martin isenburg@cs.unc.edu

  COPYRIGHT:

    copyright (C) 2003 martin isenburg (isenburg@cs.unc.edu)

    This software 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.

  CHANGE HISTORY:

    see header file

===============================================================================
*/
#include "rangeencoder.h"

#include <stdlib.h>
#include <string.h>
#include <assert.h>

RangeEncoder::RangeEncoder(FILE* fp, bool store_chars)
{
  if (fp)
  {
    this->fp = fp;
    chars = 0;
    number_chars = 0;
  }
  else
  {
    this->fp = 0;
    if (store_chars)
    {
      chars = (unsigned char*)malloc(sizeof(unsigned char)*1000);
      number_chars = 0;
      allocated_chars = 1000;
    }
    else
    {
      chars = 0;
      number_chars = 0;
    }
  }
  low = 0;                /* Full code range */
  range = TOP_VALUE;
  /* this buffer is written as first byte in the datastream (header,...) */
  buffer = HEADERBYTE;
  help = 0;               /* No bytes to follow */
  bytecount = 0;
}

void RangeEncoder::encode(RangeModel* rm, unsigned int sym)
{
  unsigned int syfreq;
  unsigned int ltfreq;
  unsigned int r, tmp;
  unsigned int lg_totf = rm->lg_totf;

  assert(sym >= 0 && sym < (unsigned int)rm->n);

  rm->getfreq(sym,&syfreq,&ltfreq);

  normalize();
  r = range >> lg_totf;
  tmp = r * ltfreq;
  low += tmp;
#ifdef EXTRAFAST
  range = r * syfreq;
#else
  if ((ltfreq+syfreq) >> lg_totf)
  {
    range -= tmp;
  }
  else
  {
    range = r * syfreq;
  }
#endif

  rm->update(sym);
}

void RangeEncoder::writeBits(unsigned int bits, unsigned int sym)
{
  assert(bits && (sym < (1u<<bits)));

  if (bits > 21) // 22 bits
  {
    writeShort(sym&65535);
    sym = sym >> 16;
    bits = bits - 16;
  }

  unsigned int r, tmp;
  normalize();
  r = range >> bits;
  tmp = r * sym;
  low += tmp;
#ifdef EXTRAFAST
  range = r;
#else
  if ((sym+1) >> bits)
  {
    range -= tmp;
  }
  else
  {
    range = r;
  }
#endif
}

void RangeEncoder::writeRange(unsigned int range, unsigned int sym)
{
  assert(range && (sym < range));

  if (range > 4194303) // 22 bits
  {
    writeShort(sym&65535);
    sym = sym >> 16;
    range = range >> 16;
    range++;
  }
  unsigned int r, tmp;
  normalize();
  r = this->range / range;
  tmp = r * sym;
  low += tmp;
#ifdef EXTRAFAST
  this->range = r;
#else
  if (sym+1 < range)
  {
    this->range = r;
  }
  else
  {
    this->range -= tmp;
  }
#endif
}

void RangeEncoder::writeRange64(U64 range, U64 sym)
{
  assert(sym < range);
  if (range > 4294967295) // 32 bits
  {
    writeInt((unsigned int)(sym&4294967295));
    sym = sym >> 32;
    range = range >> 32;
    range++;
  }
  writeRange((unsigned int)range, (unsigned int)sym);
}

void RangeEncoder::writeByte(unsigned char c)
{
  unsigned int r, tmp;
  normalize();
  r = range >> 8;
  tmp = r * (unsigned int)(c);
  low += tmp;
#ifdef EXTRAFAST
  range = r;
#else
  if (((unsigned int)(c)+1) >> 8)
  {
    range -= tmp;
  }
  else
  {
    range = r;
  }
#endif
}

void RangeEncoder::writeShort(unsigned short s)
{
  unsigned int r, tmp;
  normalize();
  r = range >> 16;
  tmp = r * (unsigned int)(s);
  low += tmp;
#ifdef EXTRAFAST
  range = r;
#else
  if (((unsigned int)(s)+1) >> 16)
  {
    range -= tmp;
  }
  else
  {
    range = r;
  }
#endif
}

void RangeEncoder::writeInt(unsigned int i)
{
  writeShort((unsigned short)(i % 65536)); // lower 16 bits
  writeShort((unsigned short)(i / 65536)); // UPPER 16 bits
}

void RangeEncoder::writeInt64(U64 l)
{
  writeInt((unsigned int)(l % 4294967296ull)); // lower 32 bits
  writeInt((unsigned int)(l / 4294967296ull)); // UPPER 32 bits
}

void RangeEncoder::writeFloat(float f)
{
  writeInt(*((unsigned int*)(&f)));
}

void RangeEncoder::writeDouble(double d)
{
  writeInt64(*((U64*)(&d)));
}

/* I do the normalization before I need a defined state instead of */
/* after messing it up. This simplifies starting and ending.       */
inline void RangeEncoder::normalize()
{
  while(range <= BOTTOM_VALUE) /* do we need renormalisation?  */
  {
    if (low < (unsigned int)0xff<<SHIFT_BITS)  /* no carry possible --> output */
    {
      outbyte(buffer);
      for(; help; help--)
      {
        outbyte(0xff);
      }
      buffer = (unsigned char)(low >> SHIFT_BITS);
    }
    else if (low & TOP_VALUE) /* carry now, no future carry */
    {
      outbyte(buffer+1);
      for(; help; help--)
      {
        outbyte(0);
      }
      buffer = (unsigned char)(low >> SHIFT_BITS);
    }
    else                      /* passes on a potential carry */
    {
      help++;
    }
    range <<= 8;
    low = (low<<8) & (TOP_VALUE-1);
    bytecount++;
  }
}

/* Finish encoding                                           */
/* actually not that many bytes need to be output, but who   */
/* cares. I output them because decode will read them :)     */
/* the return value is the number of bytes written           */
unsigned int RangeEncoder::done()
{
  unsigned int tmp;
  normalize();     /* now we have a normalized state */
  bytecount += 5;
  if ((low & (BOTTOM_VALUE-1)) < ((bytecount&0xffffffL)>>1))
  {
    tmp = low >> SHIFT_BITS;
  }
  else
  {
    tmp = (low >> SHIFT_BITS) + 1;
  }
  if (tmp > 0xff) /* we have a carry */
  {
    outbyte(buffer+1);
    for(; help; help--)
    {
      outbyte(0);
    }
  }
  else  /* no carry */
  {
    outbyte(buffer);
    for(; help; help--)
    {
      outbyte(0xff);
    }
  }
  outbyte(tmp & 0xff);
  outbyte((bytecount>>16) & 0xff);
  outbyte((bytecount>>8) & 0xff);
  outbyte(bytecount & 0xff);
  return bytecount;
}

RangeEncoder::~RangeEncoder()
{
  if (chars)
  {
    free(chars);
  }
}

unsigned char* RangeEncoder::getChars()
{
  return chars;
}

int RangeEncoder::getNumberChars()
{
  return number_chars;
}

long RangeEncoder::getNumberBits()
{
  return bytecount*8;
}

int RangeEncoder::getNumberBytes()
{
  return bytecount;
}

inline void RangeEncoder::outbyte(unsigned int c)
{
  if (fp)
  {
    fputc(c, fp);
  }
  else
  {
    if (chars)
    {
      if (number_chars == allocated_chars)
      {
        unsigned char* newchars = (unsigned char*) malloc(sizeof(unsigned char)*allocated_chars*2);
        memcpy(newchars,chars,sizeof(unsigned char)*allocated_chars);
        free(chars);
        chars = newchars;
        allocated_chars = allocated_chars*2;
      }
      chars[number_chars++] = c;
    }
  }
}
<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
// Copyright (c) 2016 by contributors. All Rights Reserved.
//
// 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.
//------------------------------------------------------------------------------

/*
Author: Chao Ma (mctt90@gmail.com)

This file is the implementation of Reader.
*/

#include "src/reader/reader.h"

#include <string.h>
#include <algorithm> // for random_shuffle

#include "src/base/file_util.h"
#include "src/base/split_string.h"

namespace xLearn {

//------------------------------------------------------------------------------
// Class register
//------------------------------------------------------------------------------
CLASS_REGISTER_IMPLEMENT_REGISTRY(xLearn_reader_registry, Reader);
REGISTER_READER("memory", InmemReader);
REGISTER_READER("disk", OndiskReader);

// Check current file format and
// return 'libsvm', 'libffm', or 'csv'.
// This function will also check if current
// data has the label y.
std::string Reader::check_file_format() {
  FILE* file = OpenFileOrDie(filename_.c_str(), "r");
  // get the first line of data
  std::string data_line;
  GetLine(file, data_line);
  Close(file);
  // Split the first line of data
  std::vector<std::string> str_list;
  SplitStringUsing(data_line, " \t", &str_list);
  // has y?
  size_t found = str_list[0].find(":");
  if (found != std::string::npos) {  // find ":", no label
    has_label_ = false;
  } else {
    has_label_ = true;
  }
  // check file format
  int count = 0;
  for (int i = 0; i < str_list[1].size(); ++i) {
    if (str_list[1][i] == ':') {
      count++;
    }
  }
  if (count == 1) {
    return "libsvm";
  } else if (count == 2) {
    return "libffm";
  } else if (count == 0){
    return "csv";
  }
  printf("[Error] Unknow file format \n");
  exit(0);
}

//------------------------------------------------------------------------------
// Implementation of InmemReader
//------------------------------------------------------------------------------

// Pre-load all the data into memory buffer (data_buf_).
// Note that this funtion will first check whether we
// can use the existing binary file. If not, reader will
// generate one automatically.
void InmemReader::Initialize(const std::string& filename) {
  CHECK_NE(filename.empty(), true)
  filename_ = filename;
  printf("First check if the text file (%s) has been already "
         "converted to binary format \n", filename.c_str());
  // HashBinary() will read the first two hash value
  // and then check it whether equal to the hash value generated
  // by HashFile() function from current txt file.
  if (hash_binary(filename_)) {
    printf("Binary file found. Skip converting text to binary \n");
    filename_ += ".bin";
    init_from_binary();
  } else {
    printf("Binary file NOT found. Convert text "
           "file to binary file \n");
    init_from_txt();
  }
}

// Check wheter current path has a binary file.
// We use double check here, that is, we first check
// the hash value of a small data block, then check the whole file.
bool InmemReader::hash_binary(const std::string& filename) {
  std::string bin_file = filename + ".bin";
  // If the ".bin" file does not exists, return false.
  if (!FileExist(bin_file.c_str())) { return false; }
  FILE* file = OpenFileOrDie(bin_file.c_str(), "r");
  // Check the first hash value
  uint64 hash_1 = 0;
  ReadDataFromDisk(file, (char*)&hash_1, sizeof(hash_1));
  if (hash_1 != HashFile(filename, true)) {
    Close(file);
    return false;
  }
  // Check the second hash value
  uint64 hash_2 = 0;
  ReadDataFromDisk(file, (char*)&hash_2, sizeof(hash_2));
  if (hash_2 != HashFile(filename, false)) {
    Close(file);
    return false;
  }
  Close(file);
  return true;
}

// In-memory Reader can be initialized from binary file.
void InmemReader::init_from_binary() {
  // Init data_buf_
  data_buf_.Deserialize(filename_);
  has_label_ = data_buf_.has_label;
  // Init data_samples_
  num_samples_ = data_buf_.row_length;
  data_samples_.ResetMatrix(num_samples_);
  // for shuffle
  order_.resize(num_samples_);
  for (int i = 0; i < order_.size(); ++i) {
    order_[i] = i;
  }
}

// Pre-load all the data to memory buffer from txt file.
void InmemReader::init_from_txt() {
  // Init parser_
  parser_ = CreateParser(check_file_format().c_str());
  if (has_label_) parser_->setLabel(true);
  else parser_->setLabel(false);
  // Init data_buf_
  char* buffer = nullptr;
  uint64 file_size = ReadFileToMemory(filename_, &buffer);
  parser_->Parse(buffer, file_size, data_buf_);
  data_buf_.SetHash(HashFile(filename_, true),
                    HashFile(filename_, false));
  data_buf_.has_label = has_label_;
  // Init data_samples_
  num_samples_ = data_buf_.row_length;
  data_samples_.ResetMatrix(num_samples_, has_label_);
  // for shuffle
  order_.resize(num_samples_);
  for (int i = 0; i < order_.size(); ++i) {
    order_[i] = i;
  }
  // Deserialize in-memory buffer to disk file.
  std::string bin_file = filename_ + ".bin";
  data_buf_.Serialize(bin_file);
  delete [] buffer;
}

// Smaple data from memory buffer.
index_t InmemReader::Samples(DMatrix* &matrix) {
  for (int i = 0; i < num_samples_; ++i) {
    if (pos_ >= data_buf_.row_length) {
      // End of the data buffer
      if (i == 0) {
        if (shuffle_) {
          random_shuffle(order_.begin(), order_.end());
        }
        matrix = nullptr;
        return 0;
      }
      break;
    }
    // Copy data between different DMatrix.
    data_samples_.row[i] = data_buf_.row[order_[pos_]];
    data_samples_.Y[i] = data_buf_.Y[order_[pos_]];
    data_samples_.norm[i] = data_buf_.norm[order_[pos_]];
    pos_++;
  }
  matrix = &data_samples_;
  return num_samples_;
}

// Return to the begining of the data buffer.
void InmemReader::Reset() { pos_ = 0; }

//------------------------------------------------------------------------------
// Implementation of OndiskReader.
//------------------------------------------------------------------------------

void OndiskReader::Initialize(const std::string& filename) {
  CHECK_NE(filename.empty(), true);
  this->filename_ = filename;
  // Init parser_
  parser_ = CreateParser(check_file_format().c_str());
  if (has_label_) parser_->setLabel(true);
  else parser_->setLabel(false);
  // Allocate memory for block
  try {
    this->block_ = (char*)malloc(block_size_*1024*1024);
  } catch (std::bad_alloc&) {
    LOG(FATAL) << "Cannot allocate enough memory for data  \
                   block. Block size: " << block_size_ << "MB";
  }
  file_ptr_ = OpenFileOrDie(filename_.c_str(), "r");
  // Pick up one thread from thread pool as back-end thread

}

// Sample data from disk file.
index_t OndiskReader::Samples(DMatrix* &matrix) {
  return 0;
}

// Return to the begining of the file
void OndiskReader::Reset() {
  int ret = fseek(file_ptr_, 0, SEEK_SET);
  if (ret != 0) {
    LOG(FATAL) << "Fail to return to the head of file.";
  }
}

// Read a block of data from disk file
void read_block(OndiskReader* reader) {
  // Convert MB to byte
  uint64 read_byte = reader->get_block_size() * 1024 * 1024;
  // Continuously read data in loop
  for (;;) {
    // We can set the length of data_sample_ to -1
    // so that the reader will know that we have already
    // finish our job, and then the reader can break.
    if (reader->get_data_sample()->row_length == -1) {
      break;
    }
    size_t ret = ReadDataFromDisk(reader->get_file_ptr(),
                                  reader->get_block(),
                                  read_byte);
    // At the end of file
    if (ret == 0) {
      // Return to the head of file.
      reader->Reset();
      // Set the length of data_sample_ to zero
      // so that we can know that we reach the end
      // of current file.
      reader->get_data_sample()->row_length = 0;
    }
  }
}

}  // namespace xLearn
<commit_msg>update<commit_after>//------------------------------------------------------------------------------
// Copyright (c) 2016 by contributors. All Rights Reserved.
//
// 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.
//------------------------------------------------------------------------------

/*
Author: Chao Ma (mctt90@gmail.com)

This file is the implementation of Reader.
*/

#include "src/reader/reader.h"

#include <string.h>
#include <algorithm> // for random_shuffle

#include "src/base/file_util.h"
#include "src/base/split_string.h"

namespace xLearn {

//------------------------------------------------------------------------------
// Class register
//------------------------------------------------------------------------------
CLASS_REGISTER_IMPLEMENT_REGISTRY(xLearn_reader_registry, Reader);
REGISTER_READER("memory", InmemReader);
REGISTER_READER("disk", OndiskReader);

// Check current file format and
// return 'libsvm', 'libffm', or 'csv'.
// This function will also check if current
// data has the label y.
std::string Reader::check_file_format() {
  FILE* file = OpenFileOrDie(filename_.c_str(), "r");
  // get the first line of data
  std::string data_line;
  GetLine(file, data_line);
  Close(file);
  // Split the first line of data
  std::vector<std::string> str_list;
  SplitStringUsing(data_line, " \t", &str_list);
  // has y?
  size_t found = str_list[0].find(":");
  if (found != std::string::npos) {  // find ":", no label
    has_label_ = false;
  } else {
    has_label_ = true;
  }
  // check file format
  int count = 0;
  for (int i = 0; i < str_list[1].size(); ++i) {
    if (str_list[1][i] == ':') {
      count++;
    }
  }
  if (count == 1) {
    return "libsvm";
  } else if (count == 2) {
    return "libffm";
  } else if (count == 0){
    return "csv";
  }
  printf("[Error] Unknow file format \n");
  exit(0);
}

//------------------------------------------------------------------------------
// Implementation of InmemReader
//------------------------------------------------------------------------------

// Pre-load all the data into memory buffer (data_buf_).
// Note that this funtion will first check whether we
// can use the existing binary file. If not, reader will
// generate one automatically.
void InmemReader::Initialize(const std::string& filename) {
  CHECK_NE(filename.empty(), true)
  filename_ = filename;
  printf("First check if the text file (%s) has been already "
         "converted to binary format \n", filename.c_str());
  // HashBinary() will read the first two hash value
  // and then check it whether equal to the hash value generated
  // by HashFile() function from current txt file.
  if (hash_binary(filename_)) {
    printf("Binary file found. Skip converting text to binary \n");
    filename_ += ".bin";
    init_from_binary();
  } else {
    printf("Binary file NOT found. Convert text "
           "file to binary file \n");
    init_from_txt();
  }
}

// Check wheter current path has a binary file.
// We use double check here, that is, we first check
// the hash value of a small data block, then check the whole file.
bool InmemReader::hash_binary(const std::string& filename) {
  std::string bin_file = filename + ".bin";
  // If the ".bin" file does not exists, return false.
  if (!FileExist(bin_file.c_str())) { return false; }
  FILE* file = OpenFileOrDie(bin_file.c_str(), "r");
  // Check the first hash value
  uint64 hash_1 = 0;
  ReadDataFromDisk(file, (char*)&hash_1, sizeof(hash_1));
  if (hash_1 != HashFile(filename, true)) {
    Close(file);
    return false;
  }
  // Check the second hash value
  uint64 hash_2 = 0;
  ReadDataFromDisk(file, (char*)&hash_2, sizeof(hash_2));
  if (hash_2 != HashFile(filename, false)) {
    Close(file);
    return false;
  }
  Close(file);
  return true;
}

// In-memory Reader can be initialized from binary file.
void InmemReader::init_from_binary() {
  // Init data_buf_
  data_buf_.Deserialize(filename_);
  has_label_ = data_buf_.has_label;
  // Init data_samples_
  num_samples_ = data_buf_.row_length;
  data_samples_.ResetMatrix(num_samples_);
  // for shuffle
  order_.resize(num_samples_);
  for (int i = 0; i < order_.size(); ++i) {
    order_[i] = i;
  }
}

// Pre-load all the data to memory buffer from txt file.
void InmemReader::init_from_txt() {
  // Init parser_
  parser_ = CreateParser(check_file_format().c_str());
  if (has_label_) parser_->setLabel(true);
  else parser_->setLabel(false);
  // Init data_buf_
  char* buffer = nullptr;
  uint64 file_size = ReadFileToMemory(filename_, &buffer);
  parser_->Parse(buffer, file_size, data_buf_);
  data_buf_.SetHash(HashFile(filename_, true),
                    HashFile(filename_, false));
  data_buf_.has_label = has_label_;
  // Init data_samples_
  num_samples_ = data_buf_.row_length;
  data_samples_.ResetMatrix(num_samples_, has_label_);
  // for shuffle
  order_.resize(num_samples_);
  for (int i = 0; i < order_.size(); ++i) {
    order_[i] = i;
  }
  // Deserialize in-memory buffer to disk file.
  std::string bin_file = filename_ + ".bin";
  data_buf_.Serialize(bin_file);
  delete [] buffer;
}

// Smaple data from memory buffer.
index_t InmemReader::Samples(DMatrix* &matrix) {
  for (int i = 0; i < num_samples_; ++i) {
    if (pos_ >= data_buf_.row_length) {
      // End of the data buffer
      if (i == 0) {
        if (shuffle_) {
          random_shuffle(order_.begin(), order_.end());
        }
        matrix = nullptr;
        return 0;
      }
      break;
    }
    // Copy data between different DMatrix.
    data_samples_.row[i] = data_buf_.row[order_[pos_]];
    data_samples_.Y[i] = data_buf_.Y[order_[pos_]];
    data_samples_.norm[i] = data_buf_.norm[order_[pos_]];
    pos_++;
  }
  matrix = &data_samples_;
  return num_samples_;
}

// Return to the begining of the data buffer.
void InmemReader::Reset() { pos_ = 0; }

//------------------------------------------------------------------------------
// Implementation of OndiskReader.
//------------------------------------------------------------------------------

void OndiskReader::Initialize(const std::string& filename) {
  CHECK_NE(filename.empty(), true);
  this->filename_ = filename;
  // Init parser_
  parser_ = CreateParser(check_file_format().c_str());
  if (has_label_) parser_->setLabel(true);
  else parser_->setLabel(false);
  // Allocate memory for block
  try {
    this->block_ = (char*)malloc(block_size_*1024*1024);
  } catch (std::bad_alloc&) {
    LOG(FATAL) << "Cannot allocate enough memory for data  \
                   block. Block size: "
               << block_size_ << "MB. "
               << "You set change the block size via configuration.";
  }
  file_ptr_ = OpenFileOrDie(filename_.c_str(), "r");
  // Pick up one thread from thread pool as back-end thread

}

// Sample data from disk file.
index_t OndiskReader::Samples(DMatrix* &matrix) {
  return 0;
}

// Return to the begining of the file
void OndiskReader::Reset() {
  int ret = fseek(file_ptr_, 0, SEEK_SET);
  if (ret != 0) {
    LOG(FATAL) << "Fail to return to the head of file.";
  }
}

// Read a block of data from disk file
void read_block(OndiskReader* reader) {
  // Convert MB to byte
  uint64 read_byte = reader->get_block_size() * 1024 * 1024;
  // Continuously read data in loop
  for (;;) {
    // We can set the length of data_sample_ to -1
    // so that the reader will know that we have already
    // finish our job, and then the reader can break.
    if (reader->get_data_sample()->row_length == -1) {
      break;
    }
    size_t ret = ReadDataFromDisk(reader->get_file_ptr(),
                                  reader->get_block(),
                                  read_byte);
    // At the end of file
    if (ret == 0) {
      // Return to the head of file.
      reader->Reset();
      // Set the length of data_sample_ to zero
      // so that we can know that we reach the end
      // of current file.
      reader->get_data_sample()->row_length = 0;
    }
  }
}

}  // namespace xLearn
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2015, Timothy Stack
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 * * Neither the name of Timothy Stack nor the names of its contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef LNAV_RELATIVE_TIME_HH
#define LNAV_RELATIVE_TIME_HH

#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include <inttypes.h>

#include <string>

#include "ptimec.hh"

class relative_time {
public:
    enum token_t {
        RTT_INVALID = -1,

        RTT_WHITE,
        RTT_AM,
        RTT_PM,
        RTT_A,
        RTT_AN,
        RTT_AT,
        RTT_TIME,
        RTT_NUMBER,
        RTT_MICROS,
        RTT_MILLIS,
        RTT_SECONDS,
        RTT_MINUTES,
        RTT_HOURS,
        RTT_DAYS,
        RTT_WEEKS,
        RTT_MONTHS,
        RTT_YEARS,
        RTT_TODAY,
        RTT_YESTERDAY,
        RTT_TOMORROW,
        RTT_NOON,
        RTT_AND,
        RTT_AGO,
        RTT_LATER,
        RTT_BEFORE,
        RTT_NOW,
        RTT_HERE,

        RTT__MAX
    };

    relative_time() {
        this->clear();
    };

    void clear() {
        memset(this->rt_field, 0, sizeof(this->rt_field));
        memset(this->rt_is_absolute, 0, sizeof(this->rt_is_absolute));
    };

    void negate() {
        for (int lpc = 0; lpc < RTF__MAX; lpc++) {
            if (!this->rt_is_absolute[lpc] && this->rt_field[lpc] != 0) {
                this->rt_field[lpc] = -this->rt_field[lpc];
            }
        }
    };

    bool is_negative() const {
        for (int lpc = 0; lpc < RTF__MAX; lpc++) {
            if (this->rt_field[lpc] < 0) {
                return true;
            }
        }
        return false;
    };

    bool is_absolute() const {
        for (int lpc = 0; lpc < RTF__MAX; lpc++) {
            if (this->rt_is_absolute[lpc]) {
                return true;
            }
        }
        return false;
    };

    bool empty() const {
        for (int lpc = 0; lpc < RTF__MAX; lpc++) {
            if (this->rt_field[lpc]) {
                return false;
            }
        }
        return true;
    };

    struct parse_error {
        int pe_column;
        std::string pe_msg;
    };

    bool parse(const char *str, size_t len, struct parse_error &pe_out);

    bool parse(const std::string &str, struct parse_error &pe_out) {
        return this->parse(str.c_str(), str.length(), pe_out);
    }

    void add(struct exttm &tm) {
        if (this->rt_is_absolute[RTF_MICROSECONDS]) {
            tm.et_nsec = this->rt_field[RTF_MICROSECONDS] * 1000;
        }
        else {
            tm.et_nsec += this->rt_field[RTF_MICROSECONDS] * 1000;
        }
        if (this->rt_is_absolute[RTF_SECONDS]) {
            tm.et_tm.tm_sec = this->rt_field[RTF_SECONDS];
        }
        else {
            tm.et_tm.tm_sec += this->rt_field[RTF_SECONDS];
        }
        if (this->rt_is_absolute[RTF_MINUTES]) {
            tm.et_tm.tm_min = this->rt_field[RTF_MINUTES];
        }
        else {
            tm.et_tm.tm_min += this->rt_field[RTF_MINUTES];
        }
        if (this->rt_is_absolute[RTF_HOURS]) {
            tm.et_tm.tm_hour = this->rt_field[RTF_HOURS];
        }
        else {
            tm.et_tm.tm_hour += this->rt_field[RTF_HOURS];
        }
        if (this->rt_is_absolute[RTF_DAYS]) {
            tm.et_tm.tm_mday = this->rt_field[RTF_DAYS];
        }
        else {
            tm.et_tm.tm_mday += this->rt_field[RTF_DAYS];
        }
        if (this->rt_is_absolute[RTF_MONTHS]) {
            tm.et_tm.tm_mon = this->rt_field[RTF_MONTHS];
        }
        else {
            tm.et_tm.tm_mon += this->rt_field[RTF_MONTHS];
        }
        if (this->rt_is_absolute[RTF_YEARS]) {
            tm.et_tm.tm_year = this->rt_field[RTF_YEARS];
        }
        else {
            tm.et_tm.tm_year += this->rt_field[RTF_YEARS];
        }
    };

    int64_t to_microseconds() {
        int64_t retval;

        retval = this->rt_field[RTF_YEARS] * 12;
        retval = (retval + this->rt_field[RTF_MONTHS]) * 30;
        retval = (retval + this->rt_field[RTF_DAYS]) * 24;
        retval = (retval + this->rt_field[RTF_HOURS]) * 60;
        retval = (retval + this->rt_field[RTF_MINUTES]) * 60;
        retval = (retval + this->rt_field[RTF_SECONDS]) * 1000 * 1000;

        return retval;
    };

    void to_timeval(struct timeval &tv_out) {
        int64_t us = this->to_microseconds();

        tv_out.tv_sec = us / (1000 * 1000);
        tv_out.tv_usec = us % (1000 * 1000);
    };

    std::string to_string() {
        char dst[128];

        snprintf(dst, sizeof(dst),
                 "%" PRId64 "%c%" PRId64 "%c%" PRId64 "%c%" PRId64 "%c%" PRId64 "%c%" PRId64 "%c%" PRId64 "%c",
                 this->rt_field[RTF_YEARS],
                 this->rt_is_absolute[RTF_YEARS] ? 'Y' : 'y',
                 this->rt_field[RTF_MONTHS],
                 this->rt_is_absolute[RTF_MONTHS] ? 'M' : 'm',
                 this->rt_field[RTF_DAYS],
                 this->rt_is_absolute[RTF_DAYS] ? 'D' : 'd',
                 this->rt_field[RTF_HOURS],
                 this->rt_is_absolute[RTF_HOURS] ? 'H' : 'h',
                 this->rt_field[RTF_MINUTES],
                 this->rt_is_absolute[RTF_MINUTES] ? 'M' : 'm',
                 this->rt_field[RTF_SECONDS],
                 this->rt_is_absolute[RTF_SECONDS] ? 'S' : 's',
                 this->rt_field[RTF_MICROSECONDS],
                 this->rt_is_absolute[RTF_MICROSECONDS] ? 'U' : 'u');
        return dst;
    };

    void rollover();

    enum {
        RTF_MICROSECONDS,
        RTF_SECONDS,
        RTF_MINUTES,
        RTF_HOURS,
        RTF_DAYS,
        RTF_MONTHS,
        RTF_YEARS,

        RTF__MAX
    };

    int64_t rt_field[RTF__MAX];
    bool rt_is_absolute[RTF__MAX];
};

#endif //LNAV_RELATIVE_TIME_HH
<commit_msg>[build] more build<commit_after>/**
 * Copyright (c) 2015, Timothy Stack
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 * * Neither the name of Timothy Stack nor the names of its contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef LNAV_RELATIVE_TIME_HH
#define LNAV_RELATIVE_TIME_HH

#include <stdio.h>
#include <string.h>
#include <sys/time.h>

#define __STDC_FORMAT_MACROS
#include <inttypes.h>

#include <string>

#include "ptimec.hh"

class relative_time {
public:
    enum token_t {
        RTT_INVALID = -1,

        RTT_WHITE,
        RTT_AM,
        RTT_PM,
        RTT_A,
        RTT_AN,
        RTT_AT,
        RTT_TIME,
        RTT_NUMBER,
        RTT_MICROS,
        RTT_MILLIS,
        RTT_SECONDS,
        RTT_MINUTES,
        RTT_HOURS,
        RTT_DAYS,
        RTT_WEEKS,
        RTT_MONTHS,
        RTT_YEARS,
        RTT_TODAY,
        RTT_YESTERDAY,
        RTT_TOMORROW,
        RTT_NOON,
        RTT_AND,
        RTT_AGO,
        RTT_LATER,
        RTT_BEFORE,
        RTT_NOW,
        RTT_HERE,

        RTT__MAX
    };

    relative_time() {
        this->clear();
    };

    void clear() {
        memset(this->rt_field, 0, sizeof(this->rt_field));
        memset(this->rt_is_absolute, 0, sizeof(this->rt_is_absolute));
    };

    void negate() {
        for (int lpc = 0; lpc < RTF__MAX; lpc++) {
            if (!this->rt_is_absolute[lpc] && this->rt_field[lpc] != 0) {
                this->rt_field[lpc] = -this->rt_field[lpc];
            }
        }
    };

    bool is_negative() const {
        for (int lpc = 0; lpc < RTF__MAX; lpc++) {
            if (this->rt_field[lpc] < 0) {
                return true;
            }
        }
        return false;
    };

    bool is_absolute() const {
        for (int lpc = 0; lpc < RTF__MAX; lpc++) {
            if (this->rt_is_absolute[lpc]) {
                return true;
            }
        }
        return false;
    };

    bool empty() const {
        for (int lpc = 0; lpc < RTF__MAX; lpc++) {
            if (this->rt_field[lpc]) {
                return false;
            }
        }
        return true;
    };

    struct parse_error {
        int pe_column;
        std::string pe_msg;
    };

    bool parse(const char *str, size_t len, struct parse_error &pe_out);

    bool parse(const std::string &str, struct parse_error &pe_out) {
        return this->parse(str.c_str(), str.length(), pe_out);
    }

    void add(struct exttm &tm) {
        if (this->rt_is_absolute[RTF_MICROSECONDS]) {
            tm.et_nsec = this->rt_field[RTF_MICROSECONDS] * 1000;
        }
        else {
            tm.et_nsec += this->rt_field[RTF_MICROSECONDS] * 1000;
        }
        if (this->rt_is_absolute[RTF_SECONDS]) {
            tm.et_tm.tm_sec = this->rt_field[RTF_SECONDS];
        }
        else {
            tm.et_tm.tm_sec += this->rt_field[RTF_SECONDS];
        }
        if (this->rt_is_absolute[RTF_MINUTES]) {
            tm.et_tm.tm_min = this->rt_field[RTF_MINUTES];
        }
        else {
            tm.et_tm.tm_min += this->rt_field[RTF_MINUTES];
        }
        if (this->rt_is_absolute[RTF_HOURS]) {
            tm.et_tm.tm_hour = this->rt_field[RTF_HOURS];
        }
        else {
            tm.et_tm.tm_hour += this->rt_field[RTF_HOURS];
        }
        if (this->rt_is_absolute[RTF_DAYS]) {
            tm.et_tm.tm_mday = this->rt_field[RTF_DAYS];
        }
        else {
            tm.et_tm.tm_mday += this->rt_field[RTF_DAYS];
        }
        if (this->rt_is_absolute[RTF_MONTHS]) {
            tm.et_tm.tm_mon = this->rt_field[RTF_MONTHS];
        }
        else {
            tm.et_tm.tm_mon += this->rt_field[RTF_MONTHS];
        }
        if (this->rt_is_absolute[RTF_YEARS]) {
            tm.et_tm.tm_year = this->rt_field[RTF_YEARS];
        }
        else {
            tm.et_tm.tm_year += this->rt_field[RTF_YEARS];
        }
    };

    int64_t to_microseconds() {
        int64_t retval;

        retval = this->rt_field[RTF_YEARS] * 12;
        retval = (retval + this->rt_field[RTF_MONTHS]) * 30;
        retval = (retval + this->rt_field[RTF_DAYS]) * 24;
        retval = (retval + this->rt_field[RTF_HOURS]) * 60;
        retval = (retval + this->rt_field[RTF_MINUTES]) * 60;
        retval = (retval + this->rt_field[RTF_SECONDS]) * 1000 * 1000;

        return retval;
    };

    void to_timeval(struct timeval &tv_out) {
        int64_t us = this->to_microseconds();

        tv_out.tv_sec = us / (1000 * 1000);
        tv_out.tv_usec = us % (1000 * 1000);
    };

    std::string to_string() {
        char dst[128];

        snprintf(dst, sizeof(dst),
                 "%" PRId64 "%c%" PRId64 "%c%" PRId64 "%c%" PRId64 "%c%" PRId64 "%c%" PRId64 "%c%" PRId64 "%c",
                 this->rt_field[RTF_YEARS],
                 this->rt_is_absolute[RTF_YEARS] ? 'Y' : 'y',
                 this->rt_field[RTF_MONTHS],
                 this->rt_is_absolute[RTF_MONTHS] ? 'M' : 'm',
                 this->rt_field[RTF_DAYS],
                 this->rt_is_absolute[RTF_DAYS] ? 'D' : 'd',
                 this->rt_field[RTF_HOURS],
                 this->rt_is_absolute[RTF_HOURS] ? 'H' : 'h',
                 this->rt_field[RTF_MINUTES],
                 this->rt_is_absolute[RTF_MINUTES] ? 'M' : 'm',
                 this->rt_field[RTF_SECONDS],
                 this->rt_is_absolute[RTF_SECONDS] ? 'S' : 's',
                 this->rt_field[RTF_MICROSECONDS],
                 this->rt_is_absolute[RTF_MICROSECONDS] ? 'U' : 'u');
        return dst;
    };

    void rollover();

    enum {
        RTF_MICROSECONDS,
        RTF_SECONDS,
        RTF_MINUTES,
        RTF_HOURS,
        RTF_DAYS,
        RTF_MONTHS,
        RTF_YEARS,

        RTF__MAX
    };

    int64_t rt_field[RTF__MAX];
    bool rt_is_absolute[RTF__MAX];
};

#endif //LNAV_RELATIVE_TIME_HH
<|endoftext|>


<commit_before><commit_msg>fix client_test build<commit_after><|endoftext|>


<commit_before><commit_msg>reverted unintentional change<commit_after><|endoftext|>


<commit_before><commit_msg>exceptions: add a constructor based on custom message<commit_after><|endoftext|>


<commit_before>#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string.hpp>
#include <string>
#include <vector>
#include <iostream>

#include "rule_checker.h"
#include <boost/tokenizer.hpp>

static std::vector<std::string> my_split(std::string str, std::string separators, size_t max_tokens, std::string cat_sym = " ")
{
	std::vector<std::string> toks;
	boost::split(toks, str, boost::is_any_of(separators), boost::token_compress_on);

	if (toks.size() > max_tokens) {
		for (size_t i = max_tokens; i < toks.size(); i++) {
			toks[max_tokens - 1] += cat_sym + toks[i];
		}

		toks.erase(toks.begin() + max_tokens, toks.end());
	}

	return toks;
}

// Perform some checks and notify a user if rule is not good enough.
static int analyze_rule(const std::string proto, std::string src_port, std::string dst_port,
		const std::vector<std::string> configured, std::string &message)
{
	int res = RULE_OK;

	if ((boost::iequals(proto, "tcp") || boost::iequals(proto, "udp")) &&
		(boost::iequals(src_port, "any") && boost::iequals(dst_port, "any"))) {
		message = "Rule without port numbers - it'll be really slow\n";
		res = RULE_HAS_WARNINGS;
	}

	if (boost::iequals(proto, "ip") &&
		(std::find(configured.begin(), configured.end(), "content")    == configured.end()) &&
		(std::find(configured.begin(), configured.end(), "uricontent") == configured.end()) &&
		(std::find(configured.begin(), configured.end(), "pcre")       == configured.end()) &&
		(std::find(configured.begin(), configured.end(), "ip_proto")   == configured.end())) {
		message += "- IP rule without content match - it's better to use firewall for this\n";
		res = RULE_HAS_WARNINGS;
	}

	if ((boost::iequals(proto, "tcp") || boost::iequals(proto, "udp")) &&
		(std::find(configured.begin(), configured.end(), "content")    == configured.end()) &&
		(std::find(configured.begin(), configured.end(), "uricontent") == configured.end()) &&
		(std::find(configured.begin(), configured.end(), "byte_test")  == configured.end()) &&
		(std::find(configured.begin(), configured.end(), "dsize")      == configured.end()) &&
		(std::find(configured.begin(), configured.end(), "flags")      == configured.end())) {
		message += "- TCP/UDP rule without deep packet checks - it's better to use firewall for this\n";
		res = RULE_HAS_WARNINGS;
	}

	if (boost::iequals(proto, "tcp") &&
		(std::find(configured.begin(), configured.end(), "flow") == configured.end())) {
		message += "- TCP protocol without flow checking. Consider adding 'flow' keyword to provide better state tracking\n";
		res = RULE_HAS_WARNINGS;
	}

	if (boost::iequals(proto, "ip") &&
		(std::find(configured.begin(), configured.end(), "flow") != configured.end())) {
		message += "- IP protocol with flow checking - consider changing protocol to TCP or UDP\n";
		res = RULE_HAS_WARNINGS;
	}

	if ((std::find(configured.begin(), configured.end(), "pcre") != configured.end()) &&
		(std::find(configured.begin(), configured.end(), "pcre") == configured.end()) &&
		(std::find(configured.begin(), configured.end(), "pcre") == configured.end())) {
		message += "- PCRE matching without 'content' or 'uricontent' keywords - it'll cause a performance hit\n";
		res = RULE_HAS_WARNINGS;
	}

	return res;
}

static int parse_and_analyze_rule_options(const std::string proto, const std::string src_port,
	const std::string dst_port, std::string str, std::string &message)
{
	// No options.
	if (str.empty()) {
		return RULE_OK;
	}

	if ((str[0] != '(') || (str[str.length() - 1] != ')')) {
		message += "- Rule options must be enclosed in '(' and ')'\n";
		return RULE_HAS_ERRORS;
	}

	// Remove surrounding braces.
	str.erase(0, 1);
	str.erase(str.length() - 1, 1);

	std::vector<std::string> options;
	std::vector<std::string> configured;

	boost::split(options, str, boost::is_any_of(";"), boost::token_compress_on);

	bool found = false;

	for (std::vector<std::string>::iterator it = options.begin(); it != options.end(); ++it) {
		std::vector<std::string> opts = my_split(*it, ":", 2, ":");
		boost::trim(opts[0]);

		if (opts[0].empty()) {
			continue;
		}

		if (opts.size() > 1) {
			boost::trim(opts[1]);
		}

		for (size_t j = 0; rule_options[j].name != NULL; j++) {
			if (boost::iequals(rule_options[j].name, opts[0])) {
				if ((std::find(configured.begin(), configured.end(), opts[0]) != configured.end()) &&
					rule_options[j].only_once) {
					message += "- Option '" + opts[0] + "' may be specified only once\n";
				}

				if (rule_options[j].args_required && (opts.size() < 2)) {
					message += "- Option '" + opts[0] + "' requires an argument\n";
				} else if (rule_options[j].arg_checker) {
					rule_options[j].arg_checker(opts[0], opts[1], message);
				}

				configured.push_back(opts[0]);
				found = true;
				break;
			}
		}

		if (!found) {
			message += "- Unknown option: " + opts[0] + "\n";
		}

		found = false;
	}

	if (boost::iequals(proto, "ip") && (!boost::iequals(src_port, "any") ||
		!boost::iequals(dst_port, "any"))) {
		message += "- IP protocol with port numbers - invalid syntax. IP protocol has no port numbers, consider using TCP or UDP\n";
	}

	if (std::find(configured.begin(), configured.end(), "sid") == configured.end()) {
		message += "- No SID number. Please add 'sid' keyword\n";
	}

	if (std::find(configured.begin(), configured.end(), "rev") == configured.end()) {
		message += "- No revision number. Please add 'rev' keyword\n";
	}

	if (std::find(configured.begin(), configured.end(), "classtype") == configured.end()) {
		message += "- No classification specified. Please add 'classtype' keyword for correct classification and priority rating\n";
	}

	if (!boost::iequals(proto, "icmp") && (std::find(configured.begin(), configured.end(), "icode") != configured.end())) {
		message += "- ICMP options on non-ICMP rule\n";
	}

	if (message.length()) {
		return RULE_HAS_ERRORS;
	}

	return analyze_rule(proto, src_port, dst_port, configured, message);
}

int process_rule(const std::string rule, std::string &message)
{
	if (rule.empty()) {
		return RULE_HAS_ERRORS;
	}

	message = "";

	std::vector<std::string> toks = my_split(rule, " \t", 8);

	if (toks.size() < 8) {
		std::cout << "Bad rule: " << rule << std::endl;
		return RULE_HAS_ERRORS;
	}

	// toks[0] - action
	// toks[1] - protocol
	// toks[2] - source address
	// toks[3] - source port
	// toks[4] - direction
	// toks[5] - destination address
	// toks[6] - destination port
	// toks[7] - rule options

	int res = parse_and_analyze_rule_options(toks[1], toks[3], toks[6], toks[7], message);

	if (message[message.length() - 1] == '\n') {
		message.erase(message.length() - 1);
	}

	return res;
}
<commit_msg>Minor change in splitting function.<commit_after>#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string.hpp>
#include <string>
#include <vector>
#include <iostream>

#include "rule_checker.h"
#include <boost/tokenizer.hpp>

static std::vector<std::string> my_split(std::string str, std::string separators, size_t max_tokens, char cat_sym = ' ')
{
	std::vector<std::string> toks;
	boost::split(toks, str, boost::is_any_of(separators), boost::token_compress_on);

	if (toks.size() > max_tokens) {
		for (size_t i = max_tokens; i < toks.size(); i++) {
			toks[max_tokens - 1] += cat_sym + toks[i];
		}

		toks.erase(toks.begin() + max_tokens, toks.end());
	}

	return toks;
}

// Perform some checks and notify a user if rule is not good enough.
static int analyze_rule(const std::string proto, std::string src_port, std::string dst_port,
		const std::vector<std::string> configured, std::string &message)
{
	int res = RULE_OK;

	if ((boost::iequals(proto, "tcp") || boost::iequals(proto, "udp")) &&
		(boost::iequals(src_port, "any") && boost::iequals(dst_port, "any"))) {
		message = "Rule without port numbers - it'll be really slow\n";
		res = RULE_HAS_WARNINGS;
	}

	if (boost::iequals(proto, "ip") &&
		(std::find(configured.begin(), configured.end(), "content")    == configured.end()) &&
		(std::find(configured.begin(), configured.end(), "uricontent") == configured.end()) &&
		(std::find(configured.begin(), configured.end(), "pcre")       == configured.end()) &&
		(std::find(configured.begin(), configured.end(), "ip_proto")   == configured.end())) {
		message += "- IP rule without content match - it's better to use firewall for this\n";
		res = RULE_HAS_WARNINGS;
	}

	if ((boost::iequals(proto, "tcp") || boost::iequals(proto, "udp")) &&
		(std::find(configured.begin(), configured.end(), "content")    == configured.end()) &&
		(std::find(configured.begin(), configured.end(), "uricontent") == configured.end()) &&
		(std::find(configured.begin(), configured.end(), "byte_test")  == configured.end()) &&
		(std::find(configured.begin(), configured.end(), "dsize")      == configured.end()) &&
		(std::find(configured.begin(), configured.end(), "flags")      == configured.end())) {
		message += "- TCP/UDP rule without deep packet checks - it's better to use firewall for this\n";
		res = RULE_HAS_WARNINGS;
	}

	if (boost::iequals(proto, "tcp") &&
		(std::find(configured.begin(), configured.end(), "flow") == configured.end())) {
		message += "- TCP protocol without flow checking. Consider adding 'flow' keyword to provide better state tracking\n";
		res = RULE_HAS_WARNINGS;
	}

	if (boost::iequals(proto, "ip") &&
		(std::find(configured.begin(), configured.end(), "flow") != configured.end())) {
		message += "- IP protocol with flow checking - consider changing protocol to TCP or UDP\n";
		res = RULE_HAS_WARNINGS;
	}

	if ((std::find(configured.begin(), configured.end(), "pcre") != configured.end()) &&
		(std::find(configured.begin(), configured.end(), "pcre") == configured.end()) &&
		(std::find(configured.begin(), configured.end(), "pcre") == configured.end())) {
		message += "- PCRE matching without 'content' or 'uricontent' keywords - it'll cause a performance hit\n";
		res = RULE_HAS_WARNINGS;
	}

	return res;
}

static int parse_and_analyze_rule_options(const std::string proto, const std::string src_port,
	const std::string dst_port, std::string str, std::string &message)
{
	// No options.
	if (str.empty()) {
		return RULE_OK;
	}

	if ((str[0] != '(') || (str[str.length() - 1] != ')')) {
		message += "- Rule options must be enclosed in '(' and ')'\n";
		return RULE_HAS_ERRORS;
	}

	// Remove surrounding braces.
	str.erase(0, 1);
	str.erase(str.length() - 1, 1);

	std::vector<std::string> options;
	std::vector<std::string> configured;

	boost::split(options, str, boost::is_any_of(";"), boost::token_compress_on);

	bool found = false;

	for (std::vector<std::string>::iterator it = options.begin(); it != options.end(); ++it) {
		std::vector<std::string> opts = my_split(*it, ":", 2, ':');
		boost::trim(opts[0]);

		if (opts[0].empty()) {
			continue;
		}

		if (opts.size() > 1) {
			boost::trim(opts[1]);
		}

		for (size_t j = 0; rule_options[j].name != NULL; j++) {
			if (boost::iequals(rule_options[j].name, opts[0])) {
				if ((std::find(configured.begin(), configured.end(), opts[0]) != configured.end()) &&
					rule_options[j].only_once) {
					message += "- Option '" + opts[0] + "' may be specified only once\n";
				}

				if (rule_options[j].args_required && (opts.size() < 2)) {
					message += "- Option '" + opts[0] + "' requires an argument\n";
				} else if (rule_options[j].arg_checker) {
					rule_options[j].arg_checker(opts[0], opts[1], message);
				}

				configured.push_back(opts[0]);
				found = true;
				break;
			}
		}

		if (!found) {
			message += "- Unknown option: " + opts[0] + "\n";
		}

		found = false;
	}

	if (boost::iequals(proto, "ip") && (!boost::iequals(src_port, "any") ||
		!boost::iequals(dst_port, "any"))) {
		message += "- IP protocol with port numbers - invalid syntax. IP protocol has no port numbers, consider using TCP or UDP\n";
	}

	if (std::find(configured.begin(), configured.end(), "sid") == configured.end()) {
		message += "- No SID number. Please add 'sid' keyword\n";
	}

	if (std::find(configured.begin(), configured.end(), "rev") == configured.end()) {
		message += "- No revision number. Please add 'rev' keyword\n";
	}

	if (std::find(configured.begin(), configured.end(), "classtype") == configured.end()) {
		message += "- No classification specified. Please add 'classtype' keyword for correct classification and priority rating\n";
	}

	if (!boost::iequals(proto, "icmp") && (std::find(configured.begin(), configured.end(), "icode") != configured.end())) {
		message += "- ICMP options on non-ICMP rule\n";
	}

	if (message.length()) {
		return RULE_HAS_ERRORS;
	}

	return analyze_rule(proto, src_port, dst_port, configured, message);
}

int process_rule(const std::string rule, std::string &message)
{
	if (rule.empty()) {
		return RULE_HAS_ERRORS;
	}

	message = "";

	std::vector<std::string> toks = my_split(rule, " \t", 8);

	if (toks.size() < 8) {
		std::cout << "Bad rule: " << rule << std::endl;
		return RULE_HAS_ERRORS;
	}

	// toks[0] - action
	// toks[1] - protocol
	// toks[2] - source address
	// toks[3] - source port
	// toks[4] - direction
	// toks[5] - destination address
	// toks[6] - destination port
	// toks[7] - rule options

	int res = parse_and_analyze_rule_options(toks[1], toks[3], toks[6], toks[7], message);

	if (message[message.length() - 1] == '\n') {
		message.erase(message.length() - 1);
	}

	return res;
}
<|endoftext|>


<commit_before>/*
Dwarf Therapist
Copyright (c) 2009 Trey Stout (chmod)

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

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

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

#include "scriptdialog.h"
#include "ui_scriptdialog.h"
#include "gamedatareader.h"
#include "labor.h"
#include "trait.h"
#include "skill.h"
#include "dwarftherapist.h"

ScriptDialog::ScriptDialog(QWidget *parent)
    : QDialog(parent)
    , ui(new Ui::ScriptDialog)
{
    ui->setupUi(this);

    GameDataReader *gdr = GameDataReader::ptr();
    QString labor_list = "
Labor Reference
"
        "
Labor ID	Labor
";
    foreach(Labor *l, gdr->get_ordered_labors()) {
        labor_list.append(QString("
%1	%2
").arg(l->labor_id, 2, 10, QChar('0')).arg(l->name));
    }
    labor_list.append("
");
    ui->text_help->append(labor_list);

    QString trait_list = "
Traits Reference
"
        "
Trait ID	Trait
";
    QPair<int, Trait*> trait_pair;
    foreach(trait_pair, gdr->get_ordered_traits()) {
        trait_list.append(QString("
%1	%2
").arg(trait_pair.second->trait_id).arg(trait_pair.second->name));
    }
    trait_list.append("
");
    ui->text_help->append(trait_list);

    QString skill_list = "
Skills Reference
"
        "
Skill ID	Skill
";
    QPair<int, QString> skill_pair;
    foreach(skill_pair, gdr->get_ordered_skills()) {
        skill_list.append(QString("
%1	%2
").arg(skill_pair.first).arg(skill_pair.second));
    }
    skill_list.append("
");
    ui->text_help->append(skill_list);

    QString attribute_list = "
Attribute Reference
"
        "
Attribute ID	Attribute
";
    QPair<int, Attribute*> att_pair;
    foreach(att_pair, gdr->get_ordered_attributes()) {
        attribute_list.append(QString("
%1	%2
").arg(att_pair.second->id).arg(att_pair.second->name));
    }
    attribute_list.append("
");
    ui->text_help->append(attribute_list);

    connect(ui->btn_apply, SIGNAL(clicked()), SLOT(apply_pressed()));
    connect(ui->btn_save, SIGNAL(clicked()), SLOT(save_pressed()));
}

void ScriptDialog::clear_script() {
    ui->script_edit->clear();
    ui->txt_script_name->clear();
    ui->lbl_save_status->clear();
    m_name = "";
}

void ScriptDialog::load_script(QString name, QString script){
    ui->script_edit->setText(script);
    m_name = name;
    ui->txt_script_name->setText(m_name);
    ui->lbl_save_status->clear();
}

void ScriptDialog::apply_pressed() {
    emit apply_script(ui->script_edit->toPlainText());
    ui->lbl_save_status->setText(tr("Script has been applied but hasn't been saved."));
}

void ScriptDialog::save_pressed() {
    QString m_old_name = m_name;
    m_name = ui->txt_script_name->text();

    QSettings *s = DT->user_settings();
    int answer = QMessageBox::Yes;

    if(m_old_name != m_name){
        s->beginGroup("filter_scripts");
        foreach(QString script_name, s->childKeys()){
            if(m_name==script_name){
                answer = QMessageBox::question(0,"Confirm Replace",
                                               tr("A script with this name already exists and will be overwritten. Continue?"),
                                               QMessageBox::Yes,QMessageBox::No);
                break;
            }
        }
        s->endGroup();
    }

    if(answer == QMessageBox::No){
        ui->lbl_save_status->setText(tr("Save cancelled."));
        return;
    }

    if(m_old_name != m_name)
        s->remove(QString("filter_scripts/%1").arg(m_old_name));

    s->setValue(QString("filter_scripts/%1").arg(m_name), ui->script_edit->toPlainText());
    emit scripts_changed();

    ui->lbl_save_status->setText(tr("Script saved successfully!"));
}
<commit_msg>fix for new scripts overwriting things it shouldn't<commit_after>/*
Dwarf Therapist
Copyright (c) 2009 Trey Stout (chmod)

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

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

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

#include "scriptdialog.h"
#include "ui_scriptdialog.h"
#include "gamedatareader.h"
#include "labor.h"
#include "trait.h"
#include "skill.h"
#include "dwarftherapist.h"

ScriptDialog::ScriptDialog(QWidget *parent)
    : QDialog(parent)
    , ui(new Ui::ScriptDialog)
{
    ui->setupUi(this);

    GameDataReader *gdr = GameDataReader::ptr();
    QString labor_list = "
Labor Reference
"
        "
Labor ID	Labor
";
    foreach(Labor *l, gdr->get_ordered_labors()) {
        labor_list.append(QString("
%1	%2
").arg(l->labor_id, 2, 10, QChar('0')).arg(l->name));
    }
    labor_list.append("
");
    ui->text_help->append(labor_list);

    QString trait_list = "
Traits Reference
"
        "
Trait ID	Trait
";
    QPair<int, Trait*> trait_pair;
    foreach(trait_pair, gdr->get_ordered_traits()) {
        trait_list.append(QString("
%1	%2
").arg(trait_pair.second->trait_id).arg(trait_pair.second->name));
    }
    trait_list.append("
");
    ui->text_help->append(trait_list);

    QString skill_list = "
Skills Reference
"
        "
Skill ID	Skill
";
    QPair<int, QString> skill_pair;
    foreach(skill_pair, gdr->get_ordered_skills()) {
        skill_list.append(QString("
%1	%2
").arg(skill_pair.first).arg(skill_pair.second));
    }
    skill_list.append("
");
    ui->text_help->append(skill_list);

    QString attribute_list = "
Attribute Reference
"
        "
Attribute ID	Attribute
";
    QPair<int, Attribute*> att_pair;
    foreach(att_pair, gdr->get_ordered_attributes()) {
        attribute_list.append(QString("
%1	%2
").arg(att_pair.second->id).arg(att_pair.second->name));
    }
    attribute_list.append("
");
    ui->text_help->append(attribute_list);

    connect(ui->btn_apply, SIGNAL(clicked()), SLOT(apply_pressed()));
    connect(ui->btn_save, SIGNAL(clicked()), SLOT(save_pressed()));
}

void ScriptDialog::clear_script() {
    ui->script_edit->clear();
    ui->txt_script_name->clear();
    ui->lbl_save_status->clear();
    m_name = "";
}

void ScriptDialog::load_script(QString name, QString script){
    ui->script_edit->setText(script);
    m_name = name;
    ui->txt_script_name->setText(m_name);
    ui->lbl_save_status->clear();
}

void ScriptDialog::apply_pressed() {
    emit apply_script(ui->script_edit->toPlainText());
    ui->lbl_save_status->setText(tr("Script has been applied but hasn't been saved."));
}

void ScriptDialog::save_pressed() {
    QString m_old_name = m_name;
    m_name = ui->txt_script_name->text();

    QSettings *s = DT->user_settings();
    int answer = QMessageBox::Yes;

    if(m_old_name != m_name){
        s->beginGroup("filter_scripts");
        foreach(QString script_name, s->childKeys()){
            if(m_name==script_name){
                answer = QMessageBox::question(0,"Confirm Replace",
                                               tr("A script with this name already exists and will be overwritten. Continue?"),
                                               QMessageBox::Yes,QMessageBox::No);
                break;
            }
        }
        s->endGroup();
    }

    if(answer == QMessageBox::No){
        ui->lbl_save_status->setText(tr("Save cancelled."));
        return;
    }

    if(m_old_name != m_name && m_old_name != "")
        s->remove(QString("filter_scripts/%1").arg(m_old_name));

    s->setValue(QString("filter_scripts/%1").arg(m_name), ui->script_edit->toPlainText());
    emit scripts_changed();

    ui->lbl_save_status->setText(tr("Script saved successfully!"));
}
<|endoftext|>


<commit_before>/*      _______   __   __   __   ______   __   __   _______   __   __
 *     / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___  /\ /  |\/ /\
 *    / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / /
 *   / / /__   / / // / // / // / /    / ___  / // ___  / // /| ' / /
 *  / /_// /\ / /_// / // / // /_/_   / / // / // /\_/ / // / |  / /
 * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ /
 * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/
 *
 * Copyright (c) 2004 darkbits                              Js_./
 * Per Larsson a.k.a finalman                          _RqZ{a<^_aa
 * Olof Naessn a.k.a jansem/yakslem                _asww7!uY`>  )\a//
 *                                                 _Qhm`] _f "'c  1!5m
 * Visit: http://guichan.darkbits.org             )Qk<P ` _: :+' .'  "{[
 *                                               .)j(] .d_/ '-(  P .   S
 * License: (BSD)                                <Td/Z <fP"5(\"??"\a.  .L
 * Redistribution and use in source and          _dV>ws?a-?'      ._/L  #'
 * binary forms, with or without                 )4d[#7r, .   '     )d`)[
 * modification, are permitted provided         _Q-5'5W..j/?'   -?!\)cam'
 * that the following conditions are met:       j<<WP+k/);.        _W=j f
 * 1. Redistributions of source code must       .$%w\/]Q  . ."'  .  mj$
 *    retain the above copyright notice,        ]E.pYY(Q]>.   a     J@\
 *    this list of conditions and the           j(]1u<sE"L,. .   ./^ ]{a
 *    following disclaimer.                     4'_uomm\.  )L);-4     (3=
 * 2. Redistributions in binary form must        )_]X{Z('a_"a7'<a"a,  ]"[
 *    reproduce the above copyright notice,       #}<]m7`Za??4,P-"'7. ).m
 *    this list of conditions and the            ]d2e)Q(<Q(  ?94   b-  LQ/
 *    following disclaimer in the                <B!</]C)d_, '(<' .f. =C+m
 *    documentation and/or other materials      .Z!=J ]e []('-4f _ ) -.)m]'
 *    provided with the distribution.          .w[5]' _[ /.)_-"+?   _/ <W"
 * 3. Neither the name of Guichan nor the      :$we` _! + _/ .        j?
 *    names of its contributors may be used     =3)= _f  (_yQmWW$#(    "
 *    to endorse or promote products derived     -   W,  sQQQQmZQ#Wwa]..
 *    from this software without specific        (js, \[QQW$QWW#?!V"".
 *    prior written permission.                    ]y:.<\..          .
 *                                                 -]n w/ '         [.
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT       )/ )/           !
 * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY         <  (; sac    ,    '
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING,               ]^ .-  %
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF            c <   r
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR            aga<  <La
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE          5%  )P'-3L
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR        _bQf` y`..)a
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,          ,J?4P'.P"_(\?d'.,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES               _Pa,)!f/<[]/  ?"
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT      _2-..:. .r+_,.. .
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,     ?a.<%"'  " -'.a_ _,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION)                     ^
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*
 * For comments regarding functions please see the header file.
 */

#include "guichan/sdl/sdlinput.hpp"
#include "guichan/exception.hpp"

namespace gcn
{
	SDLInput::SDLInput()
	{
		mMouseInWindow = true;
	}

  bool SDLInput::isKeyQueueEmpty()
  {
    return mKeyInputQueue.empty();

  } // end isKeyQueueEmpty

  KeyInput SDLInput::dequeueKeyInput()
  {
    KeyInput keyInput;

    if (mKeyInputQueue.empty())
    {
      throw GCN_EXCEPTION("SDLInput::dequeueKeyInput: the queue is empty");
    }

    keyInput = mKeyInputQueue.front();
    mKeyInputQueue.pop();

    return keyInput;

  } // end dequeueKeyInput

  bool SDLInput::isMouseQueueEmpty()
  {
    return mMouseInputQueue.empty();

  } // end isMouseQueueEmpty

  MouseInput SDLInput::dequeueMouseInput()
  {
    MouseInput mouseInput;

    if (mMouseInputQueue.empty())
    {
      throw GCN_EXCEPTION("SDLInput::dequeueMouseInput: the queue is empty");
    }

    mouseInput = mMouseInputQueue.front();
    mMouseInputQueue.pop();

    return mouseInput;

  } // end dequeueMouseInput

  void SDLInput::pushInput(SDL_Event event)
  {
    KeyInput keyInput;
    MouseInput mouseInput;

    switch (event.type)
    {
      case SDL_KEYDOWN:
        keyInput.setKey(convertKeyCharacter(event.key.keysym));
        keyInput.setType(KeyInput::PRESS);
        mKeyInputQueue.push(keyInput);
        break;

      case SDL_KEYUP:
        keyInput.setKey(convertKeyCharacter(event.key.keysym));
        keyInput.setType(KeyInput::RELEASE);
        mKeyInputQueue.push(keyInput);
        break;

      case SDL_MOUSEBUTTONDOWN:
        mMouseDown = true;
        mouseInput.x = event.button.x;
        mouseInput.y = event.button.y;
        mouseInput.setButton(convertMouseButton(event.button.button));
        mouseInput.setType(MouseInput::PRESS);
        mMouseInputQueue.push(mouseInput);
        break;

      case SDL_MOUSEBUTTONUP:
        mMouseDown = false;
        mouseInput.x = event.button.x;
        mouseInput.y = event.button.y;
        mouseInput.setButton(convertMouseButton(event.button.button));
        mouseInput.setType(MouseInput::RELEASE);
        mMouseInputQueue.push(mouseInput);

        if (!mMouseInWindow)
        {
          mouseInput.x = -1;
          mouseInput.y = -1;
          mouseInput.setButton(MouseInput::EMPTY);
          mouseInput.setType(MouseInput::MOTION);
          mMouseInputQueue.push(mouseInput);
        }
        break;

      case SDL_MOUSEMOTION:
        mouseInput.x = event.button.x;
        mouseInput.y = event.button.y;
        mouseInput.setButton(MouseInput::EMPTY);
        mouseInput.setType(MouseInput::MOTION);
        mMouseInputQueue.push(mouseInput);
        break;

      case SDL_ACTIVEEVENT:
        /*
         * This occurs when the mouse leaves the window and the Gui-chan
         * application loses its mousefocus.
         */
        if ((event.active.state & SDL_APPMOUSEFOCUS)
            && !event.active.gain)
        {
          mMouseInWindow = false;

          if (!mMouseDown)
          {
            mouseInput.x = -1;
            mouseInput.y = -1;
            mouseInput.setButton(MouseInput::EMPTY);
            mouseInput.setType(MouseInput::MOTION);
            mMouseInputQueue.push(mouseInput);
          }
        }

        if ((event.active.state & SDL_APPMOUSEFOCUS)
            && event.active.gain)
        {
          mMouseInWindow = true;
        }
        break;

    } // end switch

  } // end pushInput

  int SDLInput::convertMouseButton(int button)
  {
    switch (button)
    {
      case SDL_BUTTON_LEFT:
        return MouseInput::LEFT;
        break;
      case SDL_BUTTON_RIGHT:
        return MouseInput::RIGHT;
        break;
      case SDL_BUTTON_MIDDLE:
        return MouseInput::MIDDLE;
        break;
      case SDL_BUTTON_WHEELUP:
        return MouseInput::WHEEL_UP;
        break;
      case SDL_BUTTON_WHEELDOWN:
        return MouseInput::WHEEL_DOWN;
        break;
    }

    //TODO: Exception!

    return 0;

  } // end convertMouseButton

  Key SDLInput::convertKeyCharacter(SDL_keysym keysym)
  {
    int value = 0;
    Key key;

    if (keysym.unicode < 255)
    {
      value = (int)keysym.unicode;
    }

    switch (keysym.sym)
    {
      case SDLK_TAB:
        value = Key::TAB;
        break;
      case SDLK_LALT:
        value = Key::LEFT_ALT;
        break;
      case SDLK_RALT:
        value = Key::RIGHT_ALT;
        break;
      case SDLK_LSHIFT:
        value = Key::LEFT_SHIFT;
        break;
      case SDLK_RSHIFT:
        value = Key::RIGHT_SHIFT;
        break;
      case SDLK_LCTRL:
        value = Key::LEFT_CONTROL;
        break;
      case SDLK_RCTRL:
        value = Key::RIGHT_CONTROL;
        break;
      case SDLK_BACKSPACE:
        value = Key::BACKSPACE;
        break;
      case SDLK_PAUSE:
        value = Key::PAUSE;
        break;
      case SDLK_SPACE:
        value = Key::SPACE;
        break;
      case SDLK_ESCAPE:
        value = Key::ESCAPE;
        break;
      case SDLK_DELETE:
        value = Key::DELETE;
        break;
      case SDLK_INSERT:
        value = Key::INSERT;
        break;
      case SDLK_HOME:
        value = Key::HOME;
        break;
      case SDLK_END:
        value = Key::END;
        break;
      case SDLK_PAGEUP:
        value = Key::PAGE_UP;
        break;
      case SDLK_PRINT:
        value = Key::PRINT_SCREEN;
        break;
      case SDLK_PAGEDOWN:
        value = Key::PAGE_DOWN;
        break;
      case SDLK_F1:
        value = Key::F1;
        break;
      case SDLK_F2:
        value = Key::F2;
        break;
      case SDLK_F3:
        value = Key::F3;
        break;
      case SDLK_F4:
        value = Key::F4;
        break;
      case SDLK_F5:
        value = Key::F5;
        break;
      case SDLK_F6:
        value = Key::F6;
        break;
      case SDLK_F7:
        value = Key::F7;
        break;
      case SDLK_F8:
        value = Key::F8;
        break;
      case SDLK_F9:
        value = Key::F9;
        break;
      case SDLK_F10:
        value = Key::F10;
        break;
      case SDLK_F11:
        value = Key::F11;
        break;
      case SDLK_F12:
        value = Key::F12;
        break;
      case SDLK_F13:
        value = Key::F13;
        break;
      case SDLK_F14:
        value = Key::F14;
        break;
      case SDLK_F15:
        value = Key::F15;
        break;
      case SDLK_NUMLOCK:
        value = Key::NUM_LOCK;
        break;
      case SDLK_CAPSLOCK:
        value = Key::CAPS_LOCK;
        break;
      case SDLK_SCROLLOCK:
        value = Key::SCROLL_LOCK;
        break;
      case SDLK_RMETA:
        value = Key::RIGHT_META;
        break;
      case SDLK_LMETA:
        value = Key::LEFT_META;
        break;
      case SDLK_LSUPER:
        value = Key::LEFT_SUPER;
        break;
      case SDLK_RSUPER:
        value = Key::RIGHT_SUPER;
        break;
      case SDLK_MODE:
        value = Key::ALT_GR;
        break;
      case SDLK_UP:
        value = Key::UP;
        break;
      case SDLK_DOWN:
        value = Key::DOWN;
        break;
      case SDLK_LEFT:
        value = Key::LEFT;
        break;
      case SDLK_RIGHT:
        value = Key::RIGHT;
        break;
      case SDLK_RETURN:
        value = Key::ENTER;
        break;
      case SDLK_KP_ENTER:
        value = Key::ENTER;
        break;

      default:
        break;
    }

    if (!(keysym.mod & KMOD_NUM))
    {
      switch (keysym.sym)
      {
        case SDLK_KP0:
          value = Key::INSERT;
          break;
        case SDLK_KP1:
          value = Key::END;
          break;
        case SDLK_KP2:
          value = Key::DOWN;
          break;
        case SDLK_KP3:
          value = Key::PAGE_DOWN;
          break;
        case SDLK_KP4:
          value = Key::LEFT;
          break;
        case SDLK_KP5:
          value = 0;
          break;
        case SDLK_KP6:
          value = Key::RIGHT;
          break;
        case SDLK_KP7:
          value = Key::HOME;
          break;
        case SDLK_KP8:
          value = Key::UP;
          break;
        case SDLK_KP9:
          value = Key::PAGE_UP;
          break;
        default:
          break;
      }
    }

    key.setValue(value);
    key.setShiftPressed(keysym.mod & KMOD_SHIFT);
    key.setControlPressed(keysym.mod & KMOD_CTRL);
    key.setAltPressed(keysym.mod & KMOD_ALT);
    key.setMetaPressed(keysym.mod & KMOD_META);

    if (keysym.sym >= SDLK_KP0 && keysym.sym <= SDLK_KP_EQUALS)
    {
      key.setNumericPad(true);
    }

    return key;

  } // end convertKeyCharacter

} // end gcn
<commit_msg>Added timestamp to mouse input, doubleclicking now works (in SDL at least)<commit_after>/*      _______   __   __   __   ______   __   __   _______   __   __
 *     / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___  /\ /  |\/ /\
 *    / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / /
 *   / / /__   / / // / // / // / /    / ___  / // ___  / // /| ' / /
 *  / /_// /\ / /_// / // / // /_/_   / / // / // /\_/ / // / |  / /
 * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ /
 * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/
 *
 * Copyright (c) 2004 darkbits                              Js_./
 * Per Larsson a.k.a finalman                          _RqZ{a<^_aa
 * Olof Naessn a.k.a jansem/yakslem                _asww7!uY`>  )\a//
 *                                                 _Qhm`] _f "'c  1!5m
 * Visit: http://guichan.darkbits.org             )Qk<P ` _: :+' .'  "{[
 *                                               .)j(] .d_/ '-(  P .   S
 * License: (BSD)                                <Td/Z <fP"5(\"??"\a.  .L
 * Redistribution and use in source and          _dV>ws?a-?'      ._/L  #'
 * binary forms, with or without                 )4d[#7r, .   '     )d`)[
 * modification, are permitted provided         _Q-5'5W..j/?'   -?!\)cam'
 * that the following conditions are met:       j<<WP+k/);.        _W=j f
 * 1. Redistributions of source code must       .$%w\/]Q  . ."'  .  mj$
 *    retain the above copyright notice,        ]E.pYY(Q]>.   a     J@\
 *    this list of conditions and the           j(]1u<sE"L,. .   ./^ ]{a
 *    following disclaimer.                     4'_uomm\.  )L);-4     (3=
 * 2. Redistributions in binary form must        )_]X{Z('a_"a7'<a"a,  ]"[
 *    reproduce the above copyright notice,       #}<]m7`Za??4,P-"'7. ).m
 *    this list of conditions and the            ]d2e)Q(<Q(  ?94   b-  LQ/
 *    following disclaimer in the                <B!</]C)d_, '(<' .f. =C+m
 *    documentation and/or other materials      .Z!=J ]e []('-4f _ ) -.)m]'
 *    provided with the distribution.          .w[5]' _[ /.)_-"+?   _/ <W"
 * 3. Neither the name of Guichan nor the      :$we` _! + _/ .        j?
 *    names of its contributors may be used     =3)= _f  (_yQmWW$#(    "
 *    to endorse or promote products derived     -   W,  sQQQQmZQ#Wwa]..
 *    from this software without specific        (js, \[QQW$QWW#?!V"".
 *    prior written permission.                    ]y:.<\..          .
 *                                                 -]n w/ '         [.
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT       )/ )/           !
 * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY         <  (; sac    ,    '
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING,               ]^ .-  %
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF            c <   r
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR            aga<  <La
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE          5%  )P'-3L
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR        _bQf` y`..)a
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,          ,J?4P'.P"_(\?d'.,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES               _Pa,)!f/<[]/  ?"
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT      _2-..:. .r+_,.. .
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,     ?a.<%"'  " -'.a_ _,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION)                     ^
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*
 * For comments regarding functions please see the header file.
 */

#include "guichan/sdl/sdlinput.hpp"
#include "guichan/exception.hpp"

namespace gcn
{
	SDLInput::SDLInput()
	{
		mMouseInWindow = true;
	}

  bool SDLInput::isKeyQueueEmpty()
  {
    return mKeyInputQueue.empty();

  } // end isKeyQueueEmpty

  KeyInput SDLInput::dequeueKeyInput()
  {
    KeyInput keyInput;

    if (mKeyInputQueue.empty())
    {
      throw GCN_EXCEPTION("SDLInput::dequeueKeyInput: the queue is empty");
    }

    keyInput = mKeyInputQueue.front();
    mKeyInputQueue.pop();

    return keyInput;

  } // end dequeueKeyInput

  bool SDLInput::isMouseQueueEmpty()
  {
    return mMouseInputQueue.empty();

  } // end isMouseQueueEmpty

  MouseInput SDLInput::dequeueMouseInput()
  {
    MouseInput mouseInput;

    if (mMouseInputQueue.empty())
    {
      throw GCN_EXCEPTION("SDLInput::dequeueMouseInput: the queue is empty");
    }

    mouseInput = mMouseInputQueue.front();
    mMouseInputQueue.pop();

    return mouseInput;

  } // end dequeueMouseInput

  void SDLInput::pushInput(SDL_Event event)
  {
    KeyInput keyInput;
    MouseInput mouseInput;

    switch (event.type)
    {
      case SDL_KEYDOWN:
        keyInput.setKey(convertKeyCharacter(event.key.keysym));
        keyInput.setType(KeyInput::PRESS);
        mKeyInputQueue.push(keyInput);
        break;

      case SDL_KEYUP:
        keyInput.setKey(convertKeyCharacter(event.key.keysym));
        keyInput.setType(KeyInput::RELEASE);
        mKeyInputQueue.push(keyInput);
        break;

      case SDL_MOUSEBUTTONDOWN:
        mMouseDown = true;
        mouseInput.x = event.button.x;
        mouseInput.y = event.button.y;
        mouseInput.setButton(convertMouseButton(event.button.button));
        mouseInput.setType(MouseInput::PRESS);
		mouseInput.setTimeStamp(SDL_GetTicks());
        mMouseInputQueue.push(mouseInput);
        break;

      case SDL_MOUSEBUTTONUP:
        mMouseDown = false;
        mouseInput.x = event.button.x;
        mouseInput.y = event.button.y;
        mouseInput.setButton(convertMouseButton(event.button.button));
        mouseInput.setType(MouseInput::RELEASE);
		mouseInput.setTimeStamp(SDL_GetTicks());
        mMouseInputQueue.push(mouseInput);

        if (!mMouseInWindow)
        {
          mouseInput.x = -1;
          mouseInput.y = -1;
          mouseInput.setButton(MouseInput::EMPTY);
          mouseInput.setType(MouseInput::MOTION);
		  mouseInput.setTimeStamp(SDL_GetTicks());
          mMouseInputQueue.push(mouseInput);
        }
        break;

      case SDL_MOUSEMOTION:
        mouseInput.x = event.button.x;
        mouseInput.y = event.button.y;
        mouseInput.setButton(MouseInput::EMPTY);
        mouseInput.setType(MouseInput::MOTION);
		mouseInput.setTimeStamp(SDL_GetTicks());
        mMouseInputQueue.push(mouseInput);
        break;

      case SDL_ACTIVEEVENT:
        /*
         * This occurs when the mouse leaves the window and the Gui-chan
         * application loses its mousefocus.
         */
        if ((event.active.state & SDL_APPMOUSEFOCUS)
            && !event.active.gain)
        {
          mMouseInWindow = false;

          if (!mMouseDown)
          {
            mouseInput.x = -1;
            mouseInput.y = -1;
            mouseInput.setButton(MouseInput::EMPTY);
            mouseInput.setType(MouseInput::MOTION);
            mMouseInputQueue.push(mouseInput);
          }
        }

        if ((event.active.state & SDL_APPMOUSEFOCUS)
            && event.active.gain)
        {
          mMouseInWindow = true;
        }
        break;

    } // end switch

  } // end pushInput

  int SDLInput::convertMouseButton(int button)
  {
    switch (button)
    {
      case SDL_BUTTON_LEFT:
        return MouseInput::LEFT;
        break;
      case SDL_BUTTON_RIGHT:
        return MouseInput::RIGHT;
        break;
      case SDL_BUTTON_MIDDLE:
        return MouseInput::MIDDLE;
        break;
      case SDL_BUTTON_WHEELUP:
        return MouseInput::WHEEL_UP;
        break;
      case SDL_BUTTON_WHEELDOWN:
        return MouseInput::WHEEL_DOWN;
        break;
    }

    //TODO: Exception!

    return 0;

  } // end convertMouseButton

  Key SDLInput::convertKeyCharacter(SDL_keysym keysym)
  {
    int value = 0;
    Key key;

    if (keysym.unicode < 255)
    {
      value = (int)keysym.unicode;
    }

    switch (keysym.sym)
    {
      case SDLK_TAB:
        value = Key::TAB;
        break;
      case SDLK_LALT:
        value = Key::LEFT_ALT;
        break;
      case SDLK_RALT:
        value = Key::RIGHT_ALT;
        break;
      case SDLK_LSHIFT:
        value = Key::LEFT_SHIFT;
        break;
      case SDLK_RSHIFT:
        value = Key::RIGHT_SHIFT;
        break;
      case SDLK_LCTRL:
        value = Key::LEFT_CONTROL;
        break;
      case SDLK_RCTRL:
        value = Key::RIGHT_CONTROL;
        break;
      case SDLK_BACKSPACE:
        value = Key::BACKSPACE;
        break;
      case SDLK_PAUSE:
        value = Key::PAUSE;
        break;
      case SDLK_SPACE:
        value = Key::SPACE;
        break;
      case SDLK_ESCAPE:
        value = Key::ESCAPE;
        break;
      case SDLK_DELETE:
        value = Key::DELETE;
        break;
      case SDLK_INSERT:
        value = Key::INSERT;
        break;
      case SDLK_HOME:
        value = Key::HOME;
        break;
      case SDLK_END:
        value = Key::END;
        break;
      case SDLK_PAGEUP:
        value = Key::PAGE_UP;
        break;
      case SDLK_PRINT:
        value = Key::PRINT_SCREEN;
        break;
      case SDLK_PAGEDOWN:
        value = Key::PAGE_DOWN;
        break;
      case SDLK_F1:
        value = Key::F1;
        break;
      case SDLK_F2:
        value = Key::F2;
        break;
      case SDLK_F3:
        value = Key::F3;
        break;
      case SDLK_F4:
        value = Key::F4;
        break;
      case SDLK_F5:
        value = Key::F5;
        break;
      case SDLK_F6:
        value = Key::F6;
        break;
      case SDLK_F7:
        value = Key::F7;
        break;
      case SDLK_F8:
        value = Key::F8;
        break;
      case SDLK_F9:
        value = Key::F9;
        break;
      case SDLK_F10:
        value = Key::F10;
        break;
      case SDLK_F11:
        value = Key::F11;
        break;
      case SDLK_F12:
        value = Key::F12;
        break;
      case SDLK_F13:
        value = Key::F13;
        break;
      case SDLK_F14:
        value = Key::F14;
        break;
      case SDLK_F15:
        value = Key::F15;
        break;
      case SDLK_NUMLOCK:
        value = Key::NUM_LOCK;
        break;
      case SDLK_CAPSLOCK:
        value = Key::CAPS_LOCK;
        break;
      case SDLK_SCROLLOCK:
        value = Key::SCROLL_LOCK;
        break;
      case SDLK_RMETA:
        value = Key::RIGHT_META;
        break;
      case SDLK_LMETA:
        value = Key::LEFT_META;
        break;
      case SDLK_LSUPER:
        value = Key::LEFT_SUPER;
        break;
      case SDLK_RSUPER:
        value = Key::RIGHT_SUPER;
        break;
      case SDLK_MODE:
        value = Key::ALT_GR;
        break;
      case SDLK_UP:
        value = Key::UP;
        break;
      case SDLK_DOWN:
        value = Key::DOWN;
        break;
      case SDLK_LEFT:
        value = Key::LEFT;
        break;
      case SDLK_RIGHT:
        value = Key::RIGHT;
        break;
      case SDLK_RETURN:
        value = Key::ENTER;
        break;
      case SDLK_KP_ENTER:
        value = Key::ENTER;
        break;

      default:
        break;
    }

    if (!(keysym.mod & KMOD_NUM))
    {
      switch (keysym.sym)
      {
        case SDLK_KP0:
          value = Key::INSERT;
          break;
        case SDLK_KP1:
          value = Key::END;
          break;
        case SDLK_KP2:
          value = Key::DOWN;
          break;
        case SDLK_KP3:
          value = Key::PAGE_DOWN;
          break;
        case SDLK_KP4:
          value = Key::LEFT;
          break;
        case SDLK_KP5:
          value = 0;
          break;
        case SDLK_KP6:
          value = Key::RIGHT;
          break;
        case SDLK_KP7:
          value = Key::HOME;
          break;
        case SDLK_KP8:
          value = Key::UP;
          break;
        case SDLK_KP9:
          value = Key::PAGE_UP;
          break;
        default:
          break;
      }
    }

    key.setValue(value);
    key.setShiftPressed(keysym.mod & KMOD_SHIFT);
    key.setControlPressed(keysym.mod & KMOD_CTRL);
    key.setAltPressed(keysym.mod & KMOD_ALT);
    key.setMetaPressed(keysym.mod & KMOD_META);

    if (keysym.sym >= SDLK_KP0 && keysym.sym <= SDLK_KP_EQUALS)
    {
      key.setNumericPad(true);
    }

    return key;

  } // end convertKeyCharacter

} // end gcn
<|endoftext|>


<commit_before>#pragma once
/*
**  Copyright (C) 2012 Aldebaran Robotics
**  See COPYING for the license
*/

#ifndef _SRC_SERVERRESULT_HPP_
#define _SRC_SERVERRESULT_HPP_

#include <qi/future.hpp>
#include "message.hpp"
#include "transportsocket.hpp"

namespace qi {

  // second bounce when returned type is a future
  inline void serverResultAdapterNext(AnyReference val,// the future
    ObjectHost* host,
    TransportSocketPtr socket, const qi::MessageAddress &replyaddr)
  {
    qi::Message ret(Message::Type_Reply, replyaddr);
    TemplateTypeInterface* futureType = QI_TEMPLATE_TYPE_GET(val.type, Future);
    ObjectTypeInterface* onext = dynamic_cast<ObjectTypeInterface*>(futureType->next());
    GenericObject gfut(onext, val.value);
    if (gfut.call<bool>("hasError", 0))
    {
      ret.setType(qi::Message::Type_Error);
      ret.setError(gfut.call<std::string>("error", 0));
    }
    else
    {
      AnyValue v = gfut.call<AnyValue>("value", 0);
      ret.setValue(v, host);
    }
    if (!socket->send(ret))
      qiLogError("qimessaging.serverresult") << "Can't generate an answer for address:" << replyaddr;
  }

  inline void serverResultAdapter(qi::Future<AnyReference> future,
    ObjectHost* host, TransportSocketPtr socket, const qi::MessageAddress &replyaddr) {
    qi::Message ret(Message::Type_Reply, replyaddr);

    if (future.hasError()) {
      ret.setType(qi::Message::Type_Error);
      ret.setError(future.error());
    } else {
      qi::AnyReference val = future.value();
      TemplateTypeInterface* futureType = QI_TEMPLATE_TYPE_GET(val.type, Future);
      if (futureType)
      { // Return value is a future, bounce
        TypeInterface* next = futureType->next();
        ObjectTypeInterface* onext = dynamic_cast<ObjectTypeInterface*>(next);
        GenericObject gfut(onext, val.value);
        boost::function<void()> cb = boost::bind(serverResultAdapterNext, val, host, socket, replyaddr);
        gfut.call<void>("_connect", cb);
        return;
      }
      ret.setValue(val, host);
      val.destroy();
    }
    if (!socket->send(ret))
      qiLogError("qimessaging.serverresult") << "Can't generate an answer for address:" << replyaddr;
  }
}

#endif  // _SRC_SERVERRESULT_HPP_
<commit_msg>serverresult: be safe: catch all possibles errors<commit_after>#pragma once
/*
**  Copyright (C) 2012 Aldebaran Robotics
**  See COPYING for the license
*/

#ifndef _SRC_SERVERRESULT_HPP_
#define _SRC_SERVERRESULT_HPP_

#include <qi/future.hpp>
#include "message.hpp"
#include "transportsocket.hpp"

namespace qi {

  // second bounce when returned type is a future
  inline void serverResultAdapterNext(AnyReference val,// the future
    ObjectHost* host,
    TransportSocketPtr socket, const qi::MessageAddress &replyaddr)
  {
    qi::Message ret(Message::Type_Reply, replyaddr);
    try {
      TemplateTypeInterface* futureType = QI_TEMPLATE_TYPE_GET(val.type, Future);
      ObjectTypeInterface* onext = dynamic_cast<ObjectTypeInterface*>(futureType->next());
      GenericObject gfut(onext, val.value);
      if (gfut.call<bool>("hasError", 0))
      {
        ret.setType(qi::Message::Type_Error);
        ret.setError(gfut.call<std::string>("error", 0));
      }
      else
      {
        AnyValue v = gfut.call<AnyValue>("value", 0);
        ret.setValue(v, host);
      }
    } catch (const std::exception &e) {
      //be more than safe. we always want to nack the client in case of error
      ret.setType(qi::Message::Type_Error);
      ret.setError(std::string("Uncaught error:") + e.what());
    } catch (...) {
      //be more than safe. we always want to nack the client in case of error
      ret.setType(qi::Message::Type_Error);
      ret.setError("Unknown error caught while forwarding the answer");
    }
    if (!socket->send(ret))
      qiLogError("qimessaging.serverresult") << "Can't generate an answer for address:" << replyaddr;
  }

  inline void serverResultAdapter(qi::Future<AnyReference> future,
    ObjectHost* host, TransportSocketPtr socket, const qi::MessageAddress &replyaddr) {
    qi::Message ret(Message::Type_Reply, replyaddr);

    if (future.hasError()) {
      ret.setType(qi::Message::Type_Error);
      ret.setError(future.error());
    } else {
      try {
        qi::AnyReference val = future.value();
        TemplateTypeInterface* futureType = QI_TEMPLATE_TYPE_GET(val.type, Future);
        if (futureType)
        { // Return value is a future, bounce
          TypeInterface* next = futureType->next();
          ObjectTypeInterface* onext = dynamic_cast<ObjectTypeInterface*>(next);
          GenericObject gfut(onext, val.value);
          boost::function<void()> cb = boost::bind(serverResultAdapterNext, val, host, socket, replyaddr);
          gfut.call<void>("_connect", cb);
          return;
        }
        ret.setValue(val, host);
        //may leak if something throw inbetween.
        val.destroy();
      } catch (const std::exception &e) {
        //be more than safe. we always want to nack the client in case of error
        ret.setType(qi::Message::Type_Error);
        ret.setError(std::string("Uncaught error:") + e.what());
      } catch (...) {
        //be more than safe. we always want to nack the client in case of error
        ret.setType(qi::Message::Type_Error);
        ret.setError("Unknown error caught while sending the answer");
      }
    }
    if (!socket->send(ret))
      qiLogError("qimessaging.serverresult") << "Can't generate an answer for address:" << replyaddr;
  }
}

#endif  // _SRC_SERVERRESULT_HPP_
<|endoftext|>