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

// standard
#include <algorithm>
#include <cstring>

#ifndef ZORBA_NO_ICU
#include <unicode/ustring.h>
#endif /* ZORBA_NO_ICU */

// local
#include "cxx_util.h"
#include "utf8_util.h"

using namespace std;
#ifndef ZORBA_NO_ICU
U_NAMESPACE_USE
#endif /* ZORBA_NO_ICU */

unsigned const Mask1Byte   = 0x80;
unsigned const Mask2Bytes  = 0xC0;
unsigned const Mask3Bytes  = 0xE0;
unsigned const Mask4Bytes  = 0xF0;
unsigned const Mask5Bytes  = 0xF8;
unsigned const Mask6Bytes  = 0xFC;

namespace zorba {
namespace utf8 {

///////////////////////////////////////////////////////////////////////////////

invalid_byte::invalid_byte( char byte ) :
  invalid_argument( make_what( byte ) ),
  byte_( byte )
{
}

invalid_byte::~invalid_byte() throw() {
  // out-of-line since it's virtual
}

string invalid_byte::make_what( storage_type byte ) {
  return BUILD_STRING( '\'', byte, "': invalid UTF-8 byte" );
}

///////////////////////////////////////////////////////////////////////////////

size_type byte_pos( storage_type const *s, size_type char_pos ) {
  if ( char_pos == npos )
    return npos;
  storage_type const *p = s;
  for ( ; char_pos > 0; --char_pos ) {
    if ( !*p )
      return npos;
    p += char_length( *p );
  }
  return p - s;
}

size_type byte_pos( storage_type const *s, size_type s_len,
                    size_type char_pos ) {
  if ( char_pos == npos )
    return npos;
  storage_type const *p = s;
  storage_type const *const end = s + s_len;
  for ( ; char_pos > 0; --char_pos ) {
    if ( p >= end )
      return npos;
    p += char_length( *p );
  }
  return p - s;
}

size_type char_length( storage_type start ) {
  static char const table[] = {
    /*      0 1 2 3 4 5 6 7 8 9 A B C D E F */
    /* 0 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
    /* 1 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
    /* 2 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
    /* 3 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
    /* 4 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
    /* 5 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
    /* 6 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
    /* 7 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
    /* 8 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  // continuation bytes
    /* 9 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  //        |
    /* A */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  //        |
    /* B */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  //        |
    /* C */ 0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,  // C0 & C1 are overlong ASCII
    /* D */ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
    /* E */ 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
    /* F */ 4,4,4,4,4,4,4,4,5,5,5,5,6,6,0,0
  };
  if ( size_type const c_len = table[ static_cast<unsigned char>( start ) ] )
    return c_len;
  throw invalid_byte( start );
}

size_type char_pos( storage_type const *s, storage_type const *p ) {
  size_type pos = 0;
  while ( s < p ) {
    s += char_length( *s );
    ++pos;
  }
  return pos;
}

size_type encode( unicode::code_point cp, storage_type **ps ) {
  if ( !unicode::is_valid( cp ) )
    return 0;
  unsigned const n = cp & 0xFFFFFFFF;
  storage_type *&p = *ps, *const p0 = p;
  if ( n < 0x80 ) {
    // 0xxxxxxx
    *p++ = static_cast<storage_type>( n );
  } else if ( n < 0x800 ) {
    // 110xxxxx 10xxxxxx
    *p++ = static_cast<storage_type>( Mask2Bytes | ( n >> 6 )         );
    *p++ = static_cast<storage_type>( Mask1Byte  | ( n        & 0x3F) );
  } else if ( n < 0x10000 ) {
    // 1110xxxx 10xxxxxx 10xxxxxx
    *p++ = static_cast<storage_type>( Mask3Bytes |  (n >> 12)         );
    *p++ = static_cast<storage_type>( Mask1Byte  | ((n >>  6) & 0x3F) );
    *p++ = static_cast<storage_type>( Mask1Byte  | ( n        & 0x3F) );
  } else if ( n < 0x200000 ) {
    // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
    *p++ = static_cast<storage_type>( Mask4Bytes |  (n >> 18)         );
    *p++ = static_cast<storage_type>( Mask1Byte  | ((n >> 12) & 0x3F) );
    *p++ = static_cast<storage_type>( Mask1Byte  | ((n >>  6) & 0x3F) );
    *p++ = static_cast<storage_type>( Mask1Byte  | ( n        & 0x3F) );
  } else if ( n < 0x4000000 ) {
    // 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
    *p++ = static_cast<storage_type>( Mask5Bytes |  (n >> 24)         );
    *p++ = static_cast<storage_type>( Mask1Byte  | ((n >> 18) & 0x3F) );
    *p++ = static_cast<storage_type>( Mask1Byte  | ((n >> 12) & 0x3F) );
    *p++ = static_cast<storage_type>( Mask1Byte  | ((n >>  6) & 0x3F) );
    *p++ = static_cast<storage_type>( Mask1Byte  | ( n        & 0x3F) );
  } else if ( n < 0x8000000 ) {
    // 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
    *p++ = static_cast<storage_type>( Mask6Bytes |  (n >> 30)         );
    *p++ = static_cast<storage_type>( Mask1Byte  | ((n >> 24) & 0x3F) );
    *p++ = static_cast<storage_type>( Mask1Byte  | ((n >> 18) & 0x3F) );
    *p++ = static_cast<storage_type>( Mask1Byte  | ((n >> 12) & 0x3F) );
    *p++ = static_cast<storage_type>( Mask1Byte  | ((n >>  6) & 0x3F) );
    *p++ = static_cast<storage_type>( Mask1Byte  | ( n        & 0x3F) );
  }
  return p - p0;
}

storage_type* itou( unsigned long long n, storage_type *buf,
                    unicode::code_point zero ) {
  storage_type *s = buf;
  encoded_char_type utf8_digit[10];     // cache of UTF-8 bytes for each digit
  size_type utf8_size[10];              // number of UTF-8 bytes for each digit

  std::fill( utf8_size, utf8_size + 10, 0 );
  do {
    unsigned long long const n_prev = n;
    n /= 10;
    unsigned long long const digit = n_prev - n * 10;
    if ( !utf8_size[ digit ] ) {        // didn't cache previously: cache now
      unicode::code_point const cp = static_cast<unicode::code_point>( digit );
      utf8_size[ digit ] = encode( zero + cp, utf8_digit[ digit ] );
    }
    //
    // Copy the UTF-8 bytes into buf backwards so when we reverse the entire
    // buffer later (to reverse the digit order to put them the right way
    // around), we can treat buf as a simple string and ignore multi-byte UTF-8
    // character boundaries.
    //
    for ( size_type i = utf8_size[ digit ]; i; )
      *s++ = utf8_digit[ digit ][ --i ];

  } while ( n );

  *s = '\0';
  std::reverse( buf, s );
  return buf;
}

size_type length( storage_type const *s ) {
  size_type total_len = 0;
  while ( *s ) {
    s += char_length( *s );
    ++total_len;
  }
  return total_len;
}

size_type length( storage_type const *begin, storage_type const *end ) {
  size_type total_len = 0;
  while ( begin < end && *begin ) {
    begin += char_length( *begin );
    ++total_len;
  }
  return total_len;
}

size_type read( istream &i, storage_type **ps ) {
  char c = i.get();
  if ( !i.good() )
    return 0;
  storage_type *&p = *ps;
  *p++ = c;
  size_type const c_len = char_length( c );
  for ( size_type got = 1; got < c_len; ++got ) {
    c = i.get();
    if ( !i.good() )
      return 0;
    *p++ = c;
    if ( !is_continuation_byte( c ) )
      throw invalid_byte( c );
  }
  return c_len;
}

#ifndef ZORBA_NO_ICU

bool to_string( unicode::char_type const *in, unicode::size_type in_len,
                storage_type **out, size_type *out_len ) {
  unicode::code_point const SubChar = 0xFFFD;

  UErrorCode err = U_ZERO_ERROR;
  unicode::size_type utf8_len;
  u_strToUTF8WithSub(                   // pre-flight to get utf8_len
    nullptr, 0, &utf8_len, in, in_len, SubChar, nullptr, &err
  );
  // must not check "err" here since ICU always returns "buffer overflow"

  storage_type *const utf8_buf = new storage_type[ utf8_len ];
  err = U_ZERO_ERROR;
  u_strToUTF8WithSub(
    utf8_buf, utf8_len, nullptr, in, in_len, SubChar, nullptr, &err
  );
  if ( U_FAILURE( err ) ) {
    delete[] utf8_buf;
    return false;
  }
  *out = utf8_buf;
  if ( out_len )
    *out_len = utf8_len;
  return true;
}

#ifndef WIN32
bool to_string( wchar_t const *in, size_type in_len, storage_type **out,
                size_type *out_len ) {
  unicode::string temp;
  if ( !unicode::to_string( in, in_len, &temp ) )
    return false;
  return utf8::to_string( temp.getBuffer(), temp.length(), out, out_len );
}
#endif /* WIN32 */

bool to_wchar_t( storage_type const *in, size_type in_len, wchar_t **out,
                 unicode::size_type *out_len ) {
  unicode::string u_in;
  if ( !unicode::to_string( in, in_len, &u_in ) )
    return false;
  unicode::size_type const u_len = u_in.length();
  unicode::char_type const *const in_buf = u_in.getBuffer();

  unicode::size_type w_len;
  UErrorCode err = U_ZERO_ERROR;
  u_strToWCS( nullptr, 0, &w_len, in_buf, u_len, &err );
  if ( err == U_BUFFER_OVERFLOW_ERROR ) {
    *out = new wchar_t[ ++w_len ];
    err = U_ZERO_ERROR;
    u_strToWCS( *out, w_len, nullptr, in_buf, u_len, &err );
  }
  u_in.releaseBuffer();
  if ( U_FAILURE( err ) ) {
    delete[] *out;
    return false;
  }
  if ( out_len )
    *out_len = w_len;
  return true;
}

#endif /* ZORBA_NO_ICU */

storage_type const* validate( storage_type const *s ) {
  try {
    for ( ; *s; ++s ) {
      for ( size_type c_len = char_length( *s ); --c_len; )
        if ( !is_continuation_byte( *++s ) )
          return s;
    }
    return nullptr;
  }
  catch ( invalid_byte const& ) {
    return s;
  }
}

storage_type const* validate( storage_type const *s, size_type s_len ) {
  try {
    for ( ; s_len; ++s, --s_len ) {
      for ( size_type c_len = char_length( *s ); --c_len; )
        if ( !--s_len || !is_continuation_byte( *++s ) )
          return s;
    }
    return nullptr;
  }
  catch ( invalid_byte const& ) {
    return s;
  }
}

///////////////////////////////////////////////////////////////////////////////

} // namespace utf8
} // namespace zorba
/* vim:set et sw=2 ts=2: */
<commit_msg>Added printable_char().<commit_after>/*
 * Copyright 2006-2008 The FLWOR Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "stdafx.h"

// standard
#include <algorithm>
#include <cstring>

#ifndef ZORBA_NO_ICU
#include <unicode/ustring.h>
#endif /* ZORBA_NO_ICU */

// local
#include "ascii_util.h"
#include "cxx_util.h"
#include "utf8_util.h"

using namespace std;
#ifndef ZORBA_NO_ICU
U_NAMESPACE_USE
#endif /* ZORBA_NO_ICU */

unsigned const Mask1Byte   = 0x80;
unsigned const Mask2Bytes  = 0xC0;
unsigned const Mask3Bytes  = 0xE0;
unsigned const Mask4Bytes  = 0xF0;
unsigned const Mask5Bytes  = 0xF8;
unsigned const Mask6Bytes  = 0xFC;

namespace zorba {
namespace utf8 {

///////////////////////////////////////////////////////////////////////////////

invalid_byte::invalid_byte( char byte ) :
  invalid_argument( make_what( byte ) ),
  byte_( byte )
{
}

invalid_byte::~invalid_byte() throw() {
  // out-of-line since it's virtual
}

string invalid_byte::make_what( storage_type byte ) {
  return BUILD_STRING(
    '\'', ascii::printable_char( byte ), "': invalid UTF-8 byte"
  );
}

///////////////////////////////////////////////////////////////////////////////

size_type byte_pos( storage_type const *s, size_type char_pos ) {
  if ( char_pos == npos )
    return npos;
  storage_type const *p = s;
  for ( ; char_pos > 0; --char_pos ) {
    if ( !*p )
      return npos;
    p += char_length( *p );
  }
  return p - s;
}

size_type byte_pos( storage_type const *s, size_type s_len,
                    size_type char_pos ) {
  if ( char_pos == npos )
    return npos;
  storage_type const *p = s;
  storage_type const *const end = s + s_len;
  for ( ; char_pos > 0; --char_pos ) {
    if ( p >= end )
      return npos;
    p += char_length( *p );
  }
  return p - s;
}

size_type char_length( storage_type start ) {
  static char const table[] = {
    /*      0 1 2 3 4 5 6 7 8 9 A B C D E F */
    /* 0 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
    /* 1 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
    /* 2 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
    /* 3 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
    /* 4 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
    /* 5 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
    /* 6 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
    /* 7 */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
    /* 8 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  // continuation bytes
    /* 9 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  //        |
    /* A */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  //        |
    /* B */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  //        |
    /* C */ 0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,  // C0 & C1 are overlong ASCII
    /* D */ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
    /* E */ 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
    /* F */ 4,4,4,4,4,4,4,4,5,5,5,5,6,6,0,0
  };
  if ( size_type const c_len = table[ static_cast<unsigned char>( start ) ] )
    return c_len;
  throw invalid_byte( start );
}

size_type char_pos( storage_type const *s, storage_type const *p ) {
  size_type pos = 0;
  while ( s < p ) {
    s += char_length( *s );
    ++pos;
  }
  return pos;
}

size_type encode( unicode::code_point cp, storage_type **ps ) {
  if ( !unicode::is_valid( cp ) )
    return 0;
  unsigned const n = cp & 0xFFFFFFFF;
  storage_type *&p = *ps, *const p0 = p;
  if ( n < 0x80 ) {
    // 0xxxxxxx
    *p++ = static_cast<storage_type>( n );
  } else if ( n < 0x800 ) {
    // 110xxxxx 10xxxxxx
    *p++ = static_cast<storage_type>( Mask2Bytes | ( n >> 6 )         );
    *p++ = static_cast<storage_type>( Mask1Byte  | ( n        & 0x3F) );
  } else if ( n < 0x10000 ) {
    // 1110xxxx 10xxxxxx 10xxxxxx
    *p++ = static_cast<storage_type>( Mask3Bytes |  (n >> 12)         );
    *p++ = static_cast<storage_type>( Mask1Byte  | ((n >>  6) & 0x3F) );
    *p++ = static_cast<storage_type>( Mask1Byte  | ( n        & 0x3F) );
  } else if ( n < 0x200000 ) {
    // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
    *p++ = static_cast<storage_type>( Mask4Bytes |  (n >> 18)         );
    *p++ = static_cast<storage_type>( Mask1Byte  | ((n >> 12) & 0x3F) );
    *p++ = static_cast<storage_type>( Mask1Byte  | ((n >>  6) & 0x3F) );
    *p++ = static_cast<storage_type>( Mask1Byte  | ( n        & 0x3F) );
  } else if ( n < 0x4000000 ) {
    // 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
    *p++ = static_cast<storage_type>( Mask5Bytes |  (n >> 24)         );
    *p++ = static_cast<storage_type>( Mask1Byte  | ((n >> 18) & 0x3F) );
    *p++ = static_cast<storage_type>( Mask1Byte  | ((n >> 12) & 0x3F) );
    *p++ = static_cast<storage_type>( Mask1Byte  | ((n >>  6) & 0x3F) );
    *p++ = static_cast<storage_type>( Mask1Byte  | ( n        & 0x3F) );
  } else if ( n < 0x8000000 ) {
    // 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
    *p++ = static_cast<storage_type>( Mask6Bytes |  (n >> 30)         );
    *p++ = static_cast<storage_type>( Mask1Byte  | ((n >> 24) & 0x3F) );
    *p++ = static_cast<storage_type>( Mask1Byte  | ((n >> 18) & 0x3F) );
    *p++ = static_cast<storage_type>( Mask1Byte  | ((n >> 12) & 0x3F) );
    *p++ = static_cast<storage_type>( Mask1Byte  | ((n >>  6) & 0x3F) );
    *p++ = static_cast<storage_type>( Mask1Byte  | ( n        & 0x3F) );
  }
  return p - p0;
}

storage_type* itou( unsigned long long n, storage_type *buf,
                    unicode::code_point zero ) {
  storage_type *s = buf;
  encoded_char_type utf8_digit[10];     // cache of UTF-8 bytes for each digit
  size_type utf8_size[10];              // number of UTF-8 bytes for each digit

  std::fill( utf8_size, utf8_size + 10, 0 );
  do {
    unsigned long long const n_prev = n;
    n /= 10;
    unsigned long long const digit = n_prev - n * 10;
    if ( !utf8_size[ digit ] ) {        // didn't cache previously: cache now
      unicode::code_point const cp = static_cast<unicode::code_point>( digit );
      utf8_size[ digit ] = encode( zero + cp, utf8_digit[ digit ] );
    }
    //
    // Copy the UTF-8 bytes into buf backwards so when we reverse the entire
    // buffer later (to reverse the digit order to put them the right way
    // around), we can treat buf as a simple string and ignore multi-byte UTF-8
    // character boundaries.
    //
    for ( size_type i = utf8_size[ digit ]; i; )
      *s++ = utf8_digit[ digit ][ --i ];

  } while ( n );

  *s = '\0';
  std::reverse( buf, s );
  return buf;
}

size_type length( storage_type const *s ) {
  size_type total_len = 0;
  while ( *s ) {
    s += char_length( *s );
    ++total_len;
  }
  return total_len;
}

size_type length( storage_type const *begin, storage_type const *end ) {
  size_type total_len = 0;
  while ( begin < end && *begin ) {
    begin += char_length( *begin );
    ++total_len;
  }
  return total_len;
}

size_type read( istream &i, storage_type **ps ) {
  char c = i.get();
  if ( !i.good() )
    return 0;
  storage_type *&p = *ps;
  *p++ = c;
  size_type const c_len = char_length( c );
  for ( size_type got = 1; got < c_len; ++got ) {
    c = i.get();
    if ( !i.good() )
      return 0;
    *p++ = c;
    if ( !is_continuation_byte( c ) )
      throw invalid_byte( c );
  }
  return c_len;
}

#ifndef ZORBA_NO_ICU

bool to_string( unicode::char_type const *in, unicode::size_type in_len,
                storage_type **out, size_type *out_len ) {
  unicode::code_point const SubChar = 0xFFFD;

  UErrorCode err = U_ZERO_ERROR;
  unicode::size_type utf8_len;
  u_strToUTF8WithSub(                   // pre-flight to get utf8_len
    nullptr, 0, &utf8_len, in, in_len, SubChar, nullptr, &err
  );
  // must not check "err" here since ICU always returns "buffer overflow"

  storage_type *const utf8_buf = new storage_type[ utf8_len ];
  err = U_ZERO_ERROR;
  u_strToUTF8WithSub(
    utf8_buf, utf8_len, nullptr, in, in_len, SubChar, nullptr, &err
  );
  if ( U_FAILURE( err ) ) {
    delete[] utf8_buf;
    return false;
  }
  *out = utf8_buf;
  if ( out_len )
    *out_len = utf8_len;
  return true;
}

#ifndef WIN32
bool to_string( wchar_t const *in, size_type in_len, storage_type **out,
                size_type *out_len ) {
  unicode::string temp;
  if ( !unicode::to_string( in, in_len, &temp ) )
    return false;
  return utf8::to_string( temp.getBuffer(), temp.length(), out, out_len );
}
#endif /* WIN32 */

bool to_wchar_t( storage_type const *in, size_type in_len, wchar_t **out,
                 unicode::size_type *out_len ) {
  unicode::string u_in;
  if ( !unicode::to_string( in, in_len, &u_in ) )
    return false;
  unicode::size_type const u_len = u_in.length();
  unicode::char_type const *const in_buf = u_in.getBuffer();

  unicode::size_type w_len;
  UErrorCode err = U_ZERO_ERROR;
  u_strToWCS( nullptr, 0, &w_len, in_buf, u_len, &err );
  if ( err == U_BUFFER_OVERFLOW_ERROR ) {
    *out = new wchar_t[ ++w_len ];
    err = U_ZERO_ERROR;
    u_strToWCS( *out, w_len, nullptr, in_buf, u_len, &err );
  }
  u_in.releaseBuffer();
  if ( U_FAILURE( err ) ) {
    delete[] *out;
    return false;
  }
  if ( out_len )
    *out_len = w_len;
  return true;
}

#endif /* ZORBA_NO_ICU */

storage_type const* validate( storage_type const *s ) {
  try {
    for ( ; *s; ++s ) {
      for ( size_type c_len = char_length( *s ); --c_len; )
        if ( !is_continuation_byte( *++s ) )
          return s;
    }
    return nullptr;
  }
  catch ( invalid_byte const& ) {
    return s;
  }
}

storage_type const* validate( storage_type const *s, size_type s_len ) {
  try {
    for ( ; s_len; ++s, --s_len ) {
      for ( size_type c_len = char_length( *s ); --c_len; )
        if ( !--s_len || !is_continuation_byte( *++s ) )
          return s;
    }
    return nullptr;
  }
  catch ( invalid_byte const& ) {
    return s;
  }
}

///////////////////////////////////////////////////////////////////////////////

} // namespace utf8
} // namespace zorba
/* vim:set et sw=2 ts=2: */
<|endoftext|>


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

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

#include "util_opengl.h"
#include "util_time.h"
#include "util_view.h"

#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif

CCL_NAMESPACE_BEGIN

/* structs */

struct View {
	ViewInitFunc initf;
	ViewExitFunc exitf;
	ViewResizeFunc resize;
	ViewDisplayFunc display;
	ViewKeyboardFunc keyboard;
	ViewMotionFunc motion;

	bool first_display;
	bool redraw;

	int mouseX, mouseY;
	int mouseBut0, mouseBut2;

	int width, height;
} V;

/* public */

static void view_display_text(int x, int y, const char *text)
{
	const char *c;

	glRasterPos3f(x, y, 0);

	for(c = text; *c != '\0'; c++)
		glutBitmapCharacter(GLUT_BITMAP_HELVETICA_10, *c);
}

void view_display_info(const char *info)
{
	const int height = 20;

	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glColor4f(0.1f, 0.1f, 0.1f, 0.8f);
	glRectf(0.0f, V.height - height, V.width, V.height);
	glDisable(GL_BLEND);

	glColor3f(0.5f, 0.5f, 0.5f);

	view_display_text(10, 7 + V.height - height, info);

	glColor3f(1.0f, 1.0f, 1.0f);
}

void view_display_help()
{
	const int w = (int)((float)V.width  / 1.15f);
	const int h = (int)((float)V.height / 1.15f);

	const int x1 = (V.width - w) / 2;
	const int x2 = x1 + w;

	const int y1 = (V.height - h) / 2;
	const int y2 = y1 + h;

	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glColor4f(0.5f, 0.5f, 0.5f, 0.8f);
	glRectf(x1, y1, x2, y2);
	glDisable(GL_BLEND);

	glColor3f(0.8f, 0.8f, 0.8f);

	view_display_text(x1+20, y2-20, "Cycles Renderer");
	view_display_text(x1+20, y2-40, "(C) 2011-2014 Blender Foundation");
	view_display_text(x1+20, y2-80, "Controls:");
	view_display_text(x1+20, y2-100, "h:  Info/Help");
	view_display_text(x1+20, y2-120, "r:  Reset");
	view_display_text(x1+20, y2-140, "p:  Pause");
	view_display_text(x1+20, y2-160, "esc:  Cancel");
	view_display_text(x1+20, y2-180, "q:  Quit program");

	view_display_text(x1+20, y2-210, "i:  Interactive mode");
	view_display_text(x1+20, y2-230, "Left mouse:  Move camera");
	view_display_text(x1+20, y2-250, "Right mouse:  Rotate camera");
	view_display_text(x1+20, y2-270, "W/A/S/D:  Move camera");

	glColor3f(1.0f, 1.0f, 1.0f);
}

static void view_display()
{
	if(V.first_display) {
		if(V.initf) V.initf();
		if(V.exitf) atexit(V.exitf);

		V.first_display = false;
	}

	glClearColor(0.05f, 0.05f, 0.05f, 0.0f);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluOrtho2D(0, V.width, 0, V.height);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	glRasterPos3f(0, 0, 0);

	if(V.display)
		V.display();

	glutSwapBuffers();
}

static void view_reshape(int width, int height)
{
	if(width <= 0 || height <= 0)
		return;

	V.width = width;
	V.height = height;

	glViewport(0, 0, width, height);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	if(V.resize)
		V.resize(width, height);
}

static void view_keyboard(unsigned char key, int x, int y)
{
	if(V.keyboard)
		V.keyboard(key);

	if(key == 'm')
		printf("mouse %d %d\n", x, y);
	if(key == 'q') {
		if(V.exitf) V.exitf();
		exit(0);
	}
}

static void view_mouse(int button, int state, int x, int y)
{
	if(button == 0) {
		if(state == GLUT_DOWN) {
			V.mouseX = x;
			V.mouseY = y;
			V.mouseBut0 = 1;
		}
		else if(state == GLUT_UP) {
			V.mouseBut0 = 0;
		}
	}
	else if(button == 2) {
		if(state == GLUT_DOWN) {
			V.mouseX = x;
			V.mouseY = y;
			V.mouseBut2 = 1;
		}
		else if(state == GLUT_UP) {
			V.mouseBut2 = 0;
		}
	}
}

static void view_motion(int x, int y)
{
	const int but = V.mouseBut0? 0:2;
	const int distX = x - V.mouseX;
	const int distY = y - V.mouseY;

	if(V.motion)
		V.motion(distX, distY, but);

	V.mouseX = x;
	V.mouseY = y;
}

static void view_idle(void)
{
	if(V.redraw) {
		V.redraw = false;
		glutPostRedisplay();
	}

	time_sleep(0.1f);
}

void view_main_loop(const char *title, int width, int height,
	ViewInitFunc initf, ViewExitFunc exitf,
	ViewResizeFunc resize, ViewDisplayFunc display,
	ViewKeyboardFunc keyboard, ViewMotionFunc motion)
{
	const char *name = "app";
	char *argv = (char*)name;
	int argc = 1;

	memset(&V, 0, sizeof(V));
	V.width = width;
	V.height = height;
	V.first_display = true;
	V.redraw = false;
	V.initf = initf;
	V.exitf = exitf;
	V.resize = resize;
	V.display = display;
	V.keyboard = keyboard;
	V.motion = motion;

	glutInit(&argc, &argv);
	glutInitWindowSize(width, height);
	glutInitWindowPosition(0, 0);
	glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE|GLUT_DEPTH);
	glutCreateWindow(title);

	mxMakeCurrentContext(mxCreateContext());

	view_reshape(width, height);

	glutDisplayFunc(view_display);
	glutIdleFunc(view_idle);
	glutReshapeFunc(view_reshape);
	glutKeyboardFunc(view_keyboard);
	glutMouseFunc(view_mouse);
	glutMotionFunc(view_motion);

	glutMainLoop();
}

void view_redraw()
{
	V.redraw = true;
}

CCL_NAMESPACE_END

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

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

#include "util_opengl.h"
#include "util_time.h"
#include "util_view.h"

#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif

CCL_NAMESPACE_BEGIN

/* structs */

struct View {
	ViewInitFunc initf;
	ViewExitFunc exitf;
	ViewResizeFunc resize;
	ViewDisplayFunc display;
	ViewKeyboardFunc keyboard;
	ViewMotionFunc motion;

	bool first_display;
	bool redraw;

	int mouseX, mouseY;
	int mouseBut0, mouseBut2;

	int width, height;
} V;

/* public */

static void view_display_text(int x, int y, const char *text)
{
	const char *c;

	glRasterPos3f(x, y, 0);

	for(c = text; *c != '\0'; c++)
		glutBitmapCharacter(GLUT_BITMAP_HELVETICA_10, *c);
}

void view_display_info(const char *info)
{
	const int height = 20;

	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glColor4f(0.1f, 0.1f, 0.1f, 0.8f);
	glRectf(0.0f, V.height - height, V.width, V.height);
	glDisable(GL_BLEND);

	glColor3f(0.5f, 0.5f, 0.5f);

	view_display_text(10, 7 + V.height - height, info);

	glColor3f(1.0f, 1.0f, 1.0f);
}

void view_display_help()
{
	const int w = (int)((float)V.width  / 1.15f);
	const int h = (int)((float)V.height / 1.15f);

	const int x1 = (V.width - w) / 2;
	const int x2 = x1 + w;

	const int y1 = (V.height - h) / 2;
	const int y2 = y1 + h;

	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glColor4f(0.5f, 0.5f, 0.5f, 0.8f);
	glRectf(x1, y1, x2, y2);
	glDisable(GL_BLEND);

	glColor3f(0.8f, 0.8f, 0.8f);

	view_display_text(x1+20, y2-20, "Cycles Renderer");
	view_display_text(x1+20, y2-40, "(C) 2011-2015 Blender Foundation");
	view_display_text(x1+20, y2-80, "Controls:");
	view_display_text(x1+20, y2-100, "h:  Info/Help");
	view_display_text(x1+20, y2-120, "r:  Reset");
	view_display_text(x1+20, y2-140, "p:  Pause");
	view_display_text(x1+20, y2-160, "esc:  Cancel");
	view_display_text(x1+20, y2-180, "q:  Quit program");

	view_display_text(x1+20, y2-210, "i:  Interactive mode");
	view_display_text(x1+20, y2-230, "Left mouse:  Move camera");
	view_display_text(x1+20, y2-250, "Right mouse:  Rotate camera");
	view_display_text(x1+20, y2-270, "W/A/S/D:  Move camera");

	glColor3f(1.0f, 1.0f, 1.0f);
}

static void view_display()
{
	if(V.first_display) {
		if(V.initf) V.initf();
		if(V.exitf) atexit(V.exitf);

		V.first_display = false;
	}

	glClearColor(0.05f, 0.05f, 0.05f, 0.0f);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluOrtho2D(0, V.width, 0, V.height);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	glRasterPos3f(0, 0, 0);

	if(V.display)
		V.display();

	glutSwapBuffers();
}

static void view_reshape(int width, int height)
{
	if(width <= 0 || height <= 0)
		return;

	V.width = width;
	V.height = height;

	glViewport(0, 0, width, height);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	if(V.resize)
		V.resize(width, height);
}

static void view_keyboard(unsigned char key, int x, int y)
{
	if(V.keyboard)
		V.keyboard(key);

	if(key == 'm')
		printf("mouse %d %d\n", x, y);
	if(key == 'q') {
		if(V.exitf) V.exitf();
		exit(0);
	}
}

static void view_mouse(int button, int state, int x, int y)
{
	if(button == 0) {
		if(state == GLUT_DOWN) {
			V.mouseX = x;
			V.mouseY = y;
			V.mouseBut0 = 1;
		}
		else if(state == GLUT_UP) {
			V.mouseBut0 = 0;
		}
	}
	else if(button == 2) {
		if(state == GLUT_DOWN) {
			V.mouseX = x;
			V.mouseY = y;
			V.mouseBut2 = 1;
		}
		else if(state == GLUT_UP) {
			V.mouseBut2 = 0;
		}
	}
}

static void view_motion(int x, int y)
{
	const int but = V.mouseBut0? 0:2;
	const int distX = x - V.mouseX;
	const int distY = y - V.mouseY;

	if(V.motion)
		V.motion(distX, distY, but);

	V.mouseX = x;
	V.mouseY = y;
}

static void view_idle(void)
{
	if(V.redraw) {
		V.redraw = false;
		glutPostRedisplay();
	}

	time_sleep(0.1f);
}

void view_main_loop(const char *title, int width, int height,
	ViewInitFunc initf, ViewExitFunc exitf,
	ViewResizeFunc resize, ViewDisplayFunc display,
	ViewKeyboardFunc keyboard, ViewMotionFunc motion)
{
	const char *name = "app";
	char *argv = (char*)name;
	int argc = 1;

	memset(&V, 0, sizeof(V));
	V.width = width;
	V.height = height;
	V.first_display = true;
	V.redraw = false;
	V.initf = initf;
	V.exitf = exitf;
	V.resize = resize;
	V.display = display;
	V.keyboard = keyboard;
	V.motion = motion;

	glutInit(&argc, &argv);
	glutInitWindowSize(width, height);
	glutInitWindowPosition(0, 0);
	glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE|GLUT_DEPTH);
	glutCreateWindow(title);

	mxMakeCurrentContext(mxCreateContext());

	view_reshape(width, height);

	glutDisplayFunc(view_display);
	glutIdleFunc(view_idle);
	glutReshapeFunc(view_reshape);
	glutKeyboardFunc(view_keyboard);
	glutMouseFunc(view_mouse);
	glutMotionFunc(view_motion);

	glutMainLoop();
}

void view_redraw()
{
	V.redraw = true;
}

CCL_NAMESPACE_END

<|endoftext|>


<commit_before>// main.cc
//
// Copyright (c) 2016 Frank Lin (lin.xiaoe.f@gmail.com)
//
// 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.

// Expect command is : ./<this_cmd> --input <folder_name> --output <folder_name> --band <band> --maxzerror <max_z_error>

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

#include <string>

#include "lerc_util.h"

void create_directory(const char* directory) {
  struct stat st = {0};
  if (stat(directory, &st) == -1) {
    mkdir(directory, 0700);
  }
}

const char *get_filename_ext(const char *filename) {
  const char *dot = strrchr(filename, '.');
  if(!dot || dot == filename) return "";
  return dot + 1;
}

void list_files_do_stuff(const char* name, int level, const std::string& input_path,
                         const std::string& output_path, double max_z_error, int band,
                         bool signed_type) {
  DIR *dir;
  struct dirent *entry;

  if (!(dir = opendir(name)))
    return;
  if (!(entry = readdir(dir)))
    return;

  do {
    if (entry->d_type == DT_DIR) {
      char path[1024];
      int len = snprintf(path, sizeof(path) - 1, "%s/%s", name, entry->d_name);
      path[len] = 0;
      if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
        continue;

      // create directory in dest folder.
      std::string spec_output_folder = name;
      spec_output_folder += "/";
      spec_output_folder += entry->d_name;
      spec_output_folder.replace(spec_output_folder.begin(), spec_output_folder.begin() + input_path.size(), output_path);
      create_directory(spec_output_folder.c_str());

      // continue
      list_files_do_stuff(path, level + 1, input_path, output_path, max_z_error, band, signed_type);
    } else {
      if ((0 == strcmp("tif", get_filename_ext(entry->d_name))) ||
          (0 == strcmp("tiff", get_filename_ext(entry->d_name)))) { // allow tif and tiff extension
        // destination path
        std::string spec_output_folder = name;
        spec_output_folder += "/";
        spec_output_folder += entry->d_name;
        std::string file_path = spec_output_folder;

        size_t lastindex = spec_output_folder.find_last_of(".");
        std::string dest_file_name = spec_output_folder.substr(0, lastindex);
        dest_file_name += ".lerc";
        dest_file_name.replace(dest_file_name.begin(), dest_file_name.begin() + input_path.size(), output_path);

        bool success = gago::LercUtil::EncodeTiffOrDie(file_path,
                                                      dest_file_name,
                                                      max_z_error,
                                                      gago::LercUtil::LercVersion::V2_3,
                                                      gago::LercUtil::DataType::UNKNOWN,
                                                      band,
                                                      signed_type);
        if (!success) {
          gago::Logger::LogD("%s encode failed", file_path.c_str());
        }
      }
    }
  } while ((entry = readdir(dir)));
  closedir(dir);
}

int main(int argc, const char * argv[]) {
  std::string input_folder_path;
  std::string output_folder_path;
  uint32_t band = 0;
  double max_z_error = 0; // losses
  bool signed_type = false;

  // parse input arguments
  for (int i = 0; i < argc; ++i) {
    if (0 == strcmp("--input", argv[i])) {
      input_folder_path = argv[i + 1];
    } else if (0 == strcmp("--output", argv[i])) {
      output_folder_path = argv[i + 1];
    } else if (0 == strcmp("--band", argv[i])) {
      band = atoi(argv[i + 1]);
    } else if (0 == strcmp("--maxzerror", argv[i])) {
      max_z_error = atof(argv[i + 1]);
    } else if (0 == strcmp("--signed", argv[i])) {
      if (0 == strcmp("true", argv[i])) {
        signed_type = true;
      }
    }
  }

  // give a galance
  gago::Logger::LogD("The input folder path is %s, output lerc files will be inside %s, the TIFF band is %d, max Z error given is %f",
                     input_folder_path.c_str(),
                     output_folder_path.c_str(),
                     band,
                     max_z_error);

  // create output directory
  create_directory(output_folder_path.c_str());

  // enumerate all files in directory
  list_files_do_stuff(input_folder_path.c_str(),
                      0,
                      input_folder_path,
                      output_folder_path,
                      max_z_error,
                      band,
                      signed_type);

  gago::Logger::LogD("DONE");

  return EXIT_SUCCESS;
}
<commit_msg>Add missing headers.<commit_after>// main.cc
//
// Copyright (c) 2016 Frank Lin (lin.xiaoe.f@gmail.com)
//
// 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.

// Expect command is : ./<this_cmd> --input <folder_name> --output <folder_name> --band <band> --maxzerror <max_z_error>

#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

#include <string>

#include "lerc_util.h"

void create_directory(const char* directory) {
  struct stat st = {0};
  if (stat(directory, &st) == -1) {
    mkdir(directory, 0700);
  }
}

const char *get_filename_ext(const char *filename) {
  const char *dot = strrchr(filename, '.');
  if(!dot || dot == filename) return "";
  return dot + 1;
}

void list_files_do_stuff(const char* name, int level, const std::string& input_path,
                         const std::string& output_path, double max_z_error, int band,
                         bool signed_type) {
  DIR *dir;
  struct dirent *entry;

  if (!(dir = opendir(name)))
    return;
  if (!(entry = readdir(dir)))
    return;

  do {
    if (entry->d_type == DT_DIR) {
      char path[1024];
      int len = snprintf(path, sizeof(path) - 1, "%s/%s", name, entry->d_name);
      path[len] = 0;
      if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
        continue;

      // create directory in dest folder.
      std::string spec_output_folder = name;
      spec_output_folder += "/";
      spec_output_folder += entry->d_name;
      spec_output_folder.replace(spec_output_folder.begin(), spec_output_folder.begin() + input_path.size(), output_path);
      create_directory(spec_output_folder.c_str());

      // continue
      list_files_do_stuff(path, level + 1, input_path, output_path, max_z_error, band, signed_type);
    } else {
      if ((0 == strcmp("tif", get_filename_ext(entry->d_name))) ||
          (0 == strcmp("tiff", get_filename_ext(entry->d_name)))) { // allow tif and tiff extension
        // destination path
        std::string spec_output_folder = name;
        spec_output_folder += "/";
        spec_output_folder += entry->d_name;
        std::string file_path = spec_output_folder;

        size_t lastindex = spec_output_folder.find_last_of(".");
        std::string dest_file_name = spec_output_folder.substr(0, lastindex);
        dest_file_name += ".lerc";
        dest_file_name.replace(dest_file_name.begin(), dest_file_name.begin() + input_path.size(), output_path);

        bool success = gago::LercUtil::EncodeTiffOrDie(file_path,
                                                      dest_file_name,
                                                      max_z_error,
                                                      gago::LercUtil::LercVersion::V2_3,
                                                      gago::LercUtil::DataType::UNKNOWN,
                                                      band,
                                                      signed_type);
        if (!success) {
          gago::Logger::LogD("%s encode failed", file_path.c_str());
        }
      }
    }
  } while ((entry = readdir(dir)));
  closedir(dir);
}

int main(int argc, const char * argv[]) {
  std::string input_folder_path;
  std::string output_folder_path;
  uint32_t band = 0;
  double max_z_error = 0; // losses
  bool signed_type = false;

  // parse input arguments
  for (int i = 0; i < argc; ++i) {
    if (0 == strcmp("--input", argv[i])) {
      input_folder_path = argv[i + 1];
    } else if (0 == strcmp("--output", argv[i])) {
      output_folder_path = argv[i + 1];
    } else if (0 == strcmp("--band", argv[i])) {
      band = atoi(argv[i + 1]);
    } else if (0 == strcmp("--maxzerror", argv[i])) {
      max_z_error = atof(argv[i + 1]);
    } else if (0 == strcmp("--signed", argv[i])) {
      if (0 == strcmp("true", argv[i])) {
        signed_type = true;
      }
    }
  }

  // give a galance
  gago::Logger::LogD("The input folder path is %s, output lerc files will be inside %s, the TIFF band is %d, max Z error given is %f",
                     input_folder_path.c_str(),
                     output_folder_path.c_str(),
                     band,
                     max_z_error);

  // create output directory
  create_directory(output_folder_path.c_str());

  // enumerate all files in directory
  list_files_do_stuff(input_folder_path.c_str(),
                      0,
                      input_folder_path,
                      output_folder_path,
                      max_z_error,
                      band,
                      signed_type);

  gago::Logger::LogD("DONE");

  return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before><commit_msg>Do not log missing data requests in the for loop since data might be found from later producers; Fix log message<commit_after><|endoftext|>


<commit_before>//
// web_socket.ipp
// ~~~~~~~~~~~~~~
//
// Copyright (c) 2013 Jack (jack at gmail dot com)
//
// Distributed under the GNU Affero General Public License, Version 3.0. (See accompanying
// file LICENSE or copy at http://www.gnu.org/licenses/agpl-3.0.txt)
//

#ifndef AVWS_WEB_SOCKET_IPP
#define AVWS_WEB_SOCKET_IPP

namespace avws {

web_socket::web_socket(boost::asio::io_service &io)
	: m_io_service(io)
	, m_resolver(io)
	, m_socket(io)
{
}

web_socket::~web_socket()
{
}

void web_socket::request_options(const request_opts &options)
{

}

request_opts web_socket::request_options(void) const
{
	request_opts opt;
	return opt;
}

response_opts web_socket::response_options(void) const
{
	response_opts opt;
	return opt;
}

// 同步查询url中host信息, 并返回相应的iterator.
tcp::resolver::iterator resolve_host(tcp::resolver &resolver,
	const url &u, boost::system::error_code &ec)
{
	std::ostringstream port_string;
	port_string.imbue(std::locale("C"));
	port_string << u.port();
	tcp::resolver::query query(u.host(), port_string.str());
	return resolver.resolve(query, ec);
}

// 同步连接到endpoint_iterator所指的host.
template <typename Socket>
void connect_host(Socket &s,
	tcp::resolver::iterator &endpoint_iterator, boost::system::error_code &ec)
{
	tcp::resolver::iterator end;
	// 尝试连接解析出来的代理服务器地址.
	ec = boost::asio::error::host_not_found;
	while (ec && endpoint_iterator != end)
	{
		s.close(ec);
		s.connect(*endpoint_iterator++, ec);
	}
}

void web_socket::open(const url &u)
{
	boost::system::error_code ec;
	open(u, ec);
	if (ec)
	{
		boost::throw_exception(boost::system::system_error(ec));
	}
}

void web_socket::open(const url &u, boost::system::error_code &ec)
{
	// 保存url相关的信息.
	m_protocol = u.protocol();
	m_url = u;

	// 输出打开的链接地址.
	LOG_DEBUG("Sync open url \'" << u.to_string() << "\'");

	// 判断不支持的协议, 并返回错误.
	if (m_protocol != "ws")
	{
		LOG_ERROR("Unsupported scheme \'" << m_protocol << "\'");
		ec = boost::asio::error::operation_not_supported;
		return;
	}

	// 解析url主机
	tcp::resolver::iterator endpoint_iterator = resolve_host(m_resolver, m_url, ec);
	if (ec)	// 解析域名出错, 直接返回相关错误描述.
	{
		LOG_ERROR("Resolve \'" << m_url.host() <<
			"\', error message \'" << ec.message() << "\'");
		return;
	}

	connect_host(m_socket, endpoint_iterator, ec);
	if (ec)
	{
		LOG_ERROR("Connect to server \'" << m_url.host() << ":" << m_url.port() <<
			"\', error message \'" << ec.message() << "\'");
		return;
	}
	else
	{
		LOG_DEBUG("Connect to server \'" << m_url.host() << ":" << m_url.port() << "\'.");
	}

	// 连接成功, 开始认证逻辑.

}

template <typename Handler>
void web_socket::async_open(const url &u, BOOST_ASIO_MOVE_ARG(Handler) handler)
{

}

void web_socket::close()
{

}

void web_socket::close(boost::system::error_code &ec)
{

}
template <typename ConstBufferSequence>
std::size_t web_socket::write_some(const ConstBufferSequence &buffers)
{
	return -1;
}

template <typename ConstBufferSequence>
std::size_t web_socket::write_some(const ConstBufferSequence &buffers,
	boost::system::error_code &ec)
{
	return -1;
}

template <typename ConstBufferSequence, typename Handler>
void web_socket::async_write_some(
	const ConstBufferSequence &buffers, BOOST_ASIO_MOVE_ARG(Handler) handler)
{

}

template <typename MutableBufferSequence>
std::size_t web_socket::read_some(const MutableBufferSequence &buffers)
{
	return -1;
}

// 同步接收消息.
template <typename MutableBufferSequence>
std::size_t web_socket::read_some(const MutableBufferSequence &buffers,
	boost::system::error_code &ec)
{
	return -1;
}

// 异步接收消息.
template <typename MutableBufferSequence, typename Handler>
void web_socket::async_read_some(
	const MutableBufferSequence &buffers, BOOST_ASIO_MOVE_ARG(Handler) handler)
{

}

} // namespace avws

#endif // AVWS_WEB_SOCKET_IPP
<commit_msg>move resolve_host&connect_host function to resolve.hpp&connect.hpp<commit_after>//
// web_socket.ipp
// ~~~~~~~~~~~~~~
//
// Copyright (c) 2013 Jack (jack at gmail dot com)
//
// Distributed under the GNU Affero General Public License, Version 3.0. (See accompanying
// file LICENSE or copy at http://www.gnu.org/licenses/agpl-3.0.txt)
//

#ifndef AVWS_WEB_SOCKET_IPP
#define AVWS_WEB_SOCKET_IPP

#include "avws/resolve.hpp"
#include "avws/connect.hpp"

namespace avws {

web_socket::web_socket(boost::asio::io_service &io)
	: m_io_service(io)
	, m_resolver(io)
	, m_socket(io)
{
}

web_socket::~web_socket()
{
}

void web_socket::request_options(const request_opts &options)
{

}

request_opts web_socket::request_options(void) const
{
	request_opts opt;
	return opt;
}

response_opts web_socket::response_options(void) const
{
	response_opts opt;
	return opt;
}

void web_socket::open(const url &u)
{
	boost::system::error_code ec;
	open(u, ec);
	if (ec)
	{
		boost::throw_exception(boost::system::system_error(ec));
	}
}

void web_socket::open(const url &u, boost::system::error_code &ec)
{
	// 保存url相关的信息.
	m_protocol = u.protocol();
	m_url = u;

	// 输出打开的链接地址.
	LOG_DEBUG("Sync open url \'" << u.to_string() << "\'");

	// 判断不支持的协议, 并返回错误.
	if (m_protocol != "ws")
	{
		LOG_ERROR("Unsupported scheme \'" << m_protocol << "\'");
		ec = boost::asio::error::operation_not_supported;
		return;
	}

	// 解析url主机
	tcp::resolver::iterator endpoint_iterator = resolve_host(m_resolver, m_url, ec);
	if (ec)	// 解析域名出错, 直接返回相关错误描述.
	{
		LOG_ERROR("Resolve \'" << m_url.host() <<
			"\', error message \'" << ec.message() << "\'");
		return;
	}

	connect_host(m_socket, endpoint_iterator, ec);
	if (ec)
	{
		LOG_ERROR("Connect to server \'" << m_url.host() << ":" << m_url.port() <<
			"\', error message \'" << ec.message() << "\'");
		return;
	}
	else
	{
		LOG_DEBUG("Connect to server \'" << m_url.host() << ":" << m_url.port() << "\'.");
	}

	// 连接成功, 开始认证逻辑.

}

template <typename Handler>
void web_socket::async_open(const url &u, BOOST_ASIO_MOVE_ARG(Handler) handler)
{

}

void web_socket::close()
{

}

void web_socket::close(boost::system::error_code &ec)
{

}
template <typename ConstBufferSequence>
std::size_t web_socket::write_some(const ConstBufferSequence &buffers)
{
	return -1;
}

template <typename ConstBufferSequence>
std::size_t web_socket::write_some(const ConstBufferSequence &buffers,
	boost::system::error_code &ec)
{
	return -1;
}

template <typename ConstBufferSequence, typename Handler>
void web_socket::async_write_some(
	const ConstBufferSequence &buffers, BOOST_ASIO_MOVE_ARG(Handler) handler)
{

}

template <typename MutableBufferSequence>
std::size_t web_socket::read_some(const MutableBufferSequence &buffers)
{
	return -1;
}

// 同步接收消息.
template <typename MutableBufferSequence>
std::size_t web_socket::read_some(const MutableBufferSequence &buffers,
	boost::system::error_code &ec)
{
	return -1;
}

// 异步接收消息.
template <typename MutableBufferSequence, typename Handler>
void web_socket::async_read_some(
	const MutableBufferSequence &buffers, BOOST_ASIO_MOVE_ARG(Handler) handler)
{

}

} // namespace avws

#endif // AVWS_WEB_SOCKET_IPP
<|endoftext|>


<commit_before><commit_msg>First efforts at getting the texture cache working.  This is now avoiding doing HTTP fetches for read data.  Not certain it's completely correct but the difference is already significant.<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2011, Cornell University
// 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 HyperDex 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.

#define __STDC_LIMIT_MACROS

// C
#include <cstdio>

// POSIX
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

// po6
#include <po6/io/fd.h>

// Utils
#include "bithacks.h"

// HyperDisk
#include "shard.h"
#include "shard_constants.h"
#include "shard_snapshot.h"

e::intrusive_ptr<hyperdisk::shard>
hyperdisk :: shard :: create(const po6::io::fd& base,
                             const po6::pathname& filename)
{
    // Try removing the old shard.
    unlinkat(base.get(), filename.get(), 0);
    po6::io::fd fd(openat(base.get(), filename.get(), O_CREAT|O_EXCL|O_RDWR, S_IRWXU));

    if (fd.get() < 0)
    {
        throw po6::error(errno);
    }

    std::vector<char> buf(1 << 20, '\0');
    std::vector<iovec> iovs;
    size_t rem = FILE_SIZE;

    while (rem)
    {
        struct iovec iov;
        iov.iov_base = &buf.front();
        iov.iov_len = std::min(buf.size(), rem);
        iovs.push_back(iov);
        rem -= iov.iov_len;
    }

    if (writev(fd.get(), &iovs.front(), iovs.size()) != FILE_SIZE)
    {
        throw po6::error(errno);
    }

    // Create the shard object.
    e::intrusive_ptr<shard> ret = new shard(&fd);
    return ret;
}

hyperdisk::returncode
hyperdisk :: shard :: get(uint32_t primary_hash,
                          const e::buffer& key,
                          std::vector<e::buffer>* value,
                          uint64_t* version)
{
    size_t entry;

    if (!find_bucket(primary_hash, key, &entry))
    {
        return NOTFOUND;
    }

    const uint64_t hash_entry = m_hash_table[entry];
    const uint32_t offset = hash_entry & OFFSETMASK;

    if (offset == 0 || offset == OFFSETMASK)
    {
        return NOTFOUND;
    }

    // Load the information.
    *version = data_version(offset);
    // const size_t key_size = data_key_size(offset);
    // data_key(offset, &key);
    // ^ Skipped because find_bucket ensures that the key matches.
    data_value(offset, key.size(), value);
    return SUCCESS;
}

hyperdisk::returncode
hyperdisk :: shard :: put(uint32_t primary_hash,
                          uint32_t secondary_hash,
                          const e::buffer& key,
                          const std::vector<e::buffer>& value,
                          uint64_t version)
{
    size_t required = data_size(key, value);

    if (required + m_data_offset > FILE_SIZE)
    {
        return DATAFULL;
    }

    if (m_search_offset == SEARCH_INDEX_ENTRIES - 1)
    {
        return SEARCHFULL;
    }

    // Find the bucket.
    size_t entry;
    bool overwrite = find_bucket(primary_hash, key, &entry);

    if (entry == HASH_TABLE_SIZE)
    {
        return HASHFULL;
    }

    // Values to pack.
    uint32_t key_size = key.size();
    uint16_t value_arity = value.size();

    // Pack the values on disk.
    uint32_t curr_offset = m_data_offset;
    memmove(m_data + curr_offset, &version, sizeof(version));
    curr_offset += sizeof(version);
    memmove(m_data + curr_offset, &key_size, sizeof(key_size));
    curr_offset += sizeof(key_size);
    memmove(m_data + curr_offset, key.get(), key.size());
    curr_offset += key.size();
    memmove(m_data + curr_offset, &value_arity, sizeof(value_arity));
    curr_offset += sizeof(value_arity);

    for (size_t i = 0; i < value.size(); ++i)
    {
        uint32_t size = value[i].size();
        memmove(m_data + curr_offset, &size, sizeof(size));
        curr_offset += sizeof(size);
        memmove(m_data + curr_offset, value[i].get(), value[i].size());
        curr_offset += value[i].size();
    }

    // We need to synchronize here to ensure that all data is globally visible
    // before anything else becomes visible.
    __sync_synchronize();

    // Invalidate anything pointing to the old version.
    if (overwrite)
    {
        const uint64_t hash_entry = m_hash_table[entry];
        const uint32_t invalidated_offset = hash_entry & OFFSETMASK;
        invalidate_search_index(invalidated_offset, m_data_offset);
    }

    // Insert into the search index.
    uint64_t hashcode = secondary_hash;
    hashcode <<= 32;
    hashcode |= primary_hash;
    const uint64_t dataoffset = m_data_offset;
    m_search_index[m_search_offset * 2 + 1] = dataoffset;
    // We need to synchronize here to ensure that the data offset is visible
    // before the hash code.
    __sync_synchronize();
    m_search_index[m_search_offset * 2] = hashcode;

    // Insert into the hash table.
    uint64_t new_hash_entry = primary_hash;
    new_hash_entry <<= 32;
    new_hash_entry |= m_data_offset;
    // No need to synchronize as we assume a 64-bit platform where a word write
    // will never partially happen.
    m_hash_table[entry] = new_hash_entry;

    // Update the offsets
    ++m_search_offset;
    m_data_offset = (curr_offset + 7) & ~7; // Keep everything 8-byte aligned.
    return SUCCESS;
}

hyperdisk::returncode
hyperdisk :: shard :: del(uint32_t primary_hash,
                          const e::buffer& key)
{
    size_t entry;

    if (!find_bucket(primary_hash, key, &entry))
    {
        return NOTFOUND;
    }

    if (entry == HASH_TABLE_ENTRIES)
    {
        return NOTFOUND;
    }

    if (m_data_offset + sizeof(uint64_t) > FILE_SIZE)
    {
        return DATAFULL;
    }

    const uint32_t offset = m_hash_table[entry] & OFFSETMASK;
    assert(offset != 0 && offset != OFFSETMASK);
    invalidate_search_index(offset, m_data_offset);
    m_data_offset += sizeof(uint64_t);
    m_hash_table[entry] |= OFFSETMASK;
    return SUCCESS;
}

int
hyperdisk :: shard :: stale_space() const
{
    size_t stale = 0;
    uint32_t prev = m_search_index[1] & 0xffffffffUL;
    uint32_t cur;
    size_t i;

    for (i = 0; i < SEARCH_INDEX_ENTRIES; ++i)
    {
        cur = m_search_index[2 * i + 1] & 0xffffffffUL;

        if (cur == 0)
        {
            break;
        }

        if (m_search_index[2 * i + 1] >> 32 > 0)
        {
            stale += cur - prev;
        }

        prev = cur;
    }

    if (i == SEARCH_INDEX_ENTRIES && m_search_index[2 * i + 1] >> 32 > 0)
    {
        stale += cur - prev;
    }

    return static_cast<double>(100 * stale) / DATA_SEGMENT_SIZE;
}

int
hyperdisk :: shard :: free_space() const
{
    return static_cast<double>(100 * (m_data_offset - INDEX_SEGMENT_SIZE))
           / DATA_SEGMENT_SIZE;
}

hyperdisk::returncode
hyperdisk :: shard :: async()
{
    if (msync(m_data, FILE_SIZE, MS_ASYNC) < 0)
    {
        return SYNCFAILED;
    }

    return SUCCESS;
}

hyperdisk::returncode
hyperdisk :: shard :: sync()
{
    if (msync(m_data, FILE_SIZE, MS_SYNC) < 0)
    {
        return SYNCFAILED;
    }

    return SUCCESS;
}

e::intrusive_ptr<hyperdisk::shard_snapshot>
hyperdisk :: shard :: make_snapshot()
{
    e::intrusive_ptr<shard> d = this;
    assert(m_ref >= 2);
    e::intrusive_ptr<shard_snapshot> ret = new shard_snapshot(d);
    return ret;
}

hyperdisk :: shard :: shard(po6::io::fd* fd)
    : m_ref(0)
    , m_hash_table(NULL)
    , m_search_index(NULL)
    , m_data(NULL)
    , m_data_offset(INDEX_SEGMENT_SIZE)
    , m_search_offset(0)
{
    m_data = static_cast<char*>(mmap(NULL, FILE_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd->get(), 0));

    if (m_data == MAP_FAILED)
    {
        throw po6::error(errno);
    }

    m_hash_table = reinterpret_cast<uint64_t*>(m_data);
    m_search_index = reinterpret_cast<uint64_t*>(m_data + HASH_TABLE_SIZE);
}

hyperdisk :: shard :: ~shard()
                    throw ()
{
    munmap(m_data, FILE_SIZE);
}

size_t
hyperdisk :: shard :: data_size(const e::buffer& key,
                              const std::vector<e::buffer>& value) const
{
    size_t hypothetical_size = sizeof(uint64_t) + sizeof(uint32_t)
                             + sizeof(uint16_t) + key.size()
                             + sizeof(uint32_t) * value.size();

    for (size_t i = 0; i < value.size(); ++i)
    {
        hypothetical_size += value[i].size();
    }

    return hypothetical_size;
}

uint64_t
hyperdisk :: shard :: data_version(uint32_t offset) const
{
    assert(((offset + 7) & ~7) == offset);
    return *reinterpret_cast<uint64_t*>(m_data + offset);
}

size_t
hyperdisk :: shard :: data_key_size(uint32_t offset) const
{
    assert(((offset + 7) & ~7) == offset);
    return *reinterpret_cast<uint32_t*>(m_data + offset + sizeof(uint64_t));
}

void
hyperdisk :: shard :: data_key(uint32_t offset,
                             size_t keysize,
                             e::buffer* key) const
{
    assert(((offset + 7) & ~7) == offset);
    uint32_t cur_offset = offset + sizeof(uint64_t) + sizeof(uint32_t);
    *key = e::buffer(m_data + cur_offset, keysize);
}

void
hyperdisk :: shard :: data_value(uint32_t offset,
                               size_t keysize,
                               std::vector<e::buffer>* value) const
{
    assert(((offset + 7) & ~7) == offset);
    uint32_t cur_offset = offset + sizeof(uint64_t) + sizeof(uint32_t) + keysize;
    uint16_t num_dims;
    memmove(&num_dims, m_data + cur_offset, sizeof(uint16_t));
    cur_offset += sizeof(uint16_t);
    value->clear();

    for (uint16_t i = 0; i < num_dims; ++i)
    {
        uint32_t size;
        memmove(&size, m_data + cur_offset, sizeof(size));
        cur_offset += sizeof(size);
        value->push_back(e::buffer());
        e::buffer buf(m_data + cur_offset, size);
        value->back().swap(buf);
        cur_offset += size;
    }
}

bool
hyperdisk :: shard :: find_bucket(uint32_t primary_hash,
                                  const e::buffer& key,
                                  size_t* entry)
{
    // The first dead bucket.
    size_t dead = HASH_TABLE_ENTRIES;

    // The bucket/hash we want to use.
    *entry = HASH_INTO_TABLE(primary_hash);
    uint64_t expected = primary_hash;
    expected <<= 32;

    for (size_t off = 0; off < HASH_TABLE_ENTRIES; ++off)
    {
        size_t bucket = HASH_INTO_TABLE(*entry + off);
        const uint64_t hash_entry = m_hash_table[bucket];
        const uint64_t hash = hash_entry & ~uint64_t(OFFSETMASK);
        const uint32_t offset = hash_entry & OFFSETMASK;

        if (expected == hash && offset == OFFSETMASK)
        {
            dead = bucket;
        }
        else if (expected == hash)
        {
            const size_t key_size = data_key_size(offset);

            if (key_size == key.size() && memcmp(m_data + data_key_offset(offset), key.get(), key_size) == 0)
            {
                *entry = bucket;
                return true;
            }
        }

        if (offset == 0)
        {
            if (dead == HASH_TABLE_ENTRIES)
            {
                *entry = bucket;
            }
            else
            {
                *entry = dead;
            }

            return false;
        }

        if (offset == OFFSETMASK && dead == HASH_TABLE_ENTRIES)
        {
            dead = bucket;
        }
    }

    *entry = dead;
    return false;
}

void
hyperdisk :: shard :: invalidate_search_index(uint32_t to_invalidate, uint32_t invalidate_with)
{
    int64_t low = 0;
    int64_t high = SEARCH_INDEX_ENTRIES - 1;

    while (low <= high)
    {
        int64_t mid = low + ((high - low) / 2);
        const uint32_t mid_offset = m_search_index[mid * 2 + 1] & 0xffffffffUL;

        if (mid_offset == 0 || mid_offset > to_invalidate)
        {
            high = mid - 1;
        }
        else if (mid_offset < to_invalidate)
        {
            low = mid + 1;
        }
        else if (mid_offset == to_invalidate)
        {
            uint64_t new_entry = invalidate_with;
            new_entry <<= 32;
            new_entry |= to_invalidate;
            m_search_index[mid * 2 + 1] |= new_entry;
            return;
        }
    }
}
<commit_msg>When returning stale space, consider stale entries.<commit_after>// Copyright (c) 2011, Cornell University
// 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 HyperDex 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.

#define __STDC_LIMIT_MACROS

// C
#include <cstdio>

// POSIX
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

// po6
#include <po6/io/fd.h>

// Utils
#include "bithacks.h"

// HyperDisk
#include "shard.h"
#include "shard_constants.h"
#include "shard_snapshot.h"

e::intrusive_ptr<hyperdisk::shard>
hyperdisk :: shard :: create(const po6::io::fd& base,
                             const po6::pathname& filename)
{
    // Try removing the old shard.
    unlinkat(base.get(), filename.get(), 0);
    po6::io::fd fd(openat(base.get(), filename.get(), O_CREAT|O_EXCL|O_RDWR, S_IRWXU));

    if (fd.get() < 0)
    {
        throw po6::error(errno);
    }

    std::vector<char> buf(1 << 20, '\0');
    std::vector<iovec> iovs;
    size_t rem = FILE_SIZE;

    while (rem)
    {
        struct iovec iov;
        iov.iov_base = &buf.front();
        iov.iov_len = std::min(buf.size(), rem);
        iovs.push_back(iov);
        rem -= iov.iov_len;
    }

    if (writev(fd.get(), &iovs.front(), iovs.size()) != FILE_SIZE)
    {
        throw po6::error(errno);
    }

    // Create the shard object.
    e::intrusive_ptr<shard> ret = new shard(&fd);
    return ret;
}

hyperdisk::returncode
hyperdisk :: shard :: get(uint32_t primary_hash,
                          const e::buffer& key,
                          std::vector<e::buffer>* value,
                          uint64_t* version)
{
    size_t entry;

    if (!find_bucket(primary_hash, key, &entry))
    {
        return NOTFOUND;
    }

    const uint64_t hash_entry = m_hash_table[entry];
    const uint32_t offset = hash_entry & OFFSETMASK;

    if (offset == 0 || offset == OFFSETMASK)
    {
        return NOTFOUND;
    }

    // Load the information.
    *version = data_version(offset);
    // const size_t key_size = data_key_size(offset);
    // data_key(offset, &key);
    // ^ Skipped because find_bucket ensures that the key matches.
    data_value(offset, key.size(), value);
    return SUCCESS;
}

hyperdisk::returncode
hyperdisk :: shard :: put(uint32_t primary_hash,
                          uint32_t secondary_hash,
                          const e::buffer& key,
                          const std::vector<e::buffer>& value,
                          uint64_t version)
{
    size_t required = data_size(key, value);

    if (required + m_data_offset > FILE_SIZE)
    {
        return DATAFULL;
    }

    if (m_search_offset == SEARCH_INDEX_ENTRIES - 1)
    {
        return SEARCHFULL;
    }

    // Find the bucket.
    size_t entry;
    bool overwrite = find_bucket(primary_hash, key, &entry);

    if (entry == HASH_TABLE_SIZE)
    {
        return HASHFULL;
    }

    // Values to pack.
    uint32_t key_size = key.size();
    uint16_t value_arity = value.size();

    // Pack the values on disk.
    uint32_t curr_offset = m_data_offset;
    memmove(m_data + curr_offset, &version, sizeof(version));
    curr_offset += sizeof(version);
    memmove(m_data + curr_offset, &key_size, sizeof(key_size));
    curr_offset += sizeof(key_size);
    memmove(m_data + curr_offset, key.get(), key.size());
    curr_offset += key.size();
    memmove(m_data + curr_offset, &value_arity, sizeof(value_arity));
    curr_offset += sizeof(value_arity);

    for (size_t i = 0; i < value.size(); ++i)
    {
        uint32_t size = value[i].size();
        memmove(m_data + curr_offset, &size, sizeof(size));
        curr_offset += sizeof(size);
        memmove(m_data + curr_offset, value[i].get(), value[i].size());
        curr_offset += value[i].size();
    }

    // We need to synchronize here to ensure that all data is globally visible
    // before anything else becomes visible.
    __sync_synchronize();

    // Invalidate anything pointing to the old version.
    if (overwrite)
    {
        const uint64_t hash_entry = m_hash_table[entry];
        const uint32_t invalidated_offset = hash_entry & OFFSETMASK;
        invalidate_search_index(invalidated_offset, m_data_offset);
    }

    // Insert into the search index.
    uint64_t hashcode = secondary_hash;
    hashcode <<= 32;
    hashcode |= primary_hash;
    const uint64_t dataoffset = m_data_offset;
    m_search_index[m_search_offset * 2 + 1] = dataoffset;
    // We need to synchronize here to ensure that the data offset is visible
    // before the hash code.
    __sync_synchronize();
    m_search_index[m_search_offset * 2] = hashcode;

    // Insert into the hash table.
    uint64_t new_hash_entry = primary_hash;
    new_hash_entry <<= 32;
    new_hash_entry |= m_data_offset;
    // No need to synchronize as we assume a 64-bit platform where a word write
    // will never partially happen.
    m_hash_table[entry] = new_hash_entry;

    // Update the offsets
    ++m_search_offset;
    m_data_offset = (curr_offset + 7) & ~7; // Keep everything 8-byte aligned.
    return SUCCESS;
}

hyperdisk::returncode
hyperdisk :: shard :: del(uint32_t primary_hash,
                          const e::buffer& key)
{
    size_t entry;

    if (!find_bucket(primary_hash, key, &entry))
    {
        return NOTFOUND;
    }

    if (entry == HASH_TABLE_ENTRIES)
    {
        return NOTFOUND;
    }

    if (m_data_offset + sizeof(uint64_t) > FILE_SIZE)
    {
        return DATAFULL;
    }

    const uint32_t offset = m_hash_table[entry] & OFFSETMASK;
    assert(offset != 0 && offset != OFFSETMASK);
    invalidate_search_index(offset, m_data_offset);
    m_data_offset += sizeof(uint64_t);
    m_hash_table[entry] |= OFFSETMASK;
    return SUCCESS;
}

int
hyperdisk :: shard :: stale_space() const
{
    size_t stale_data = 0;
    size_t stale_num = 0;
    uint32_t prev = m_search_index[1] & 0xffffffffUL;
    uint32_t cur;
    size_t i;

    for (i = 0; i < SEARCH_INDEX_ENTRIES; ++i)
    {
        cur = m_search_index[2 * i + 1] & 0xffffffffUL;

        if (cur == 0)
        {
            break;
        }

        if (m_search_index[2 * i + 1] >> 32 > 0)
        {
            stale_data += cur - prev;
            ++stale_num;
        }

        prev = cur;
    }

    if (i == SEARCH_INDEX_ENTRIES && m_search_index[2 * i + 1] >> 32 > 0)
    {
        stale_data += cur - prev;
        ++stale_num;
    }

    double data = 100.0 * static_cast<double>(stale_data) / DATA_SEGMENT_SIZE;
    double num = 100.0 * static_cast<double>(stale_num) / SEARCH_INDEX_ENTRIES;
    return std::max(data, num);
}

int
hyperdisk :: shard :: free_space() const
{
    return static_cast<double>(100 * (m_data_offset - INDEX_SEGMENT_SIZE))
           / DATA_SEGMENT_SIZE;
}

hyperdisk::returncode
hyperdisk :: shard :: async()
{
    if (msync(m_data, FILE_SIZE, MS_ASYNC) < 0)
    {
        return SYNCFAILED;
    }

    return SUCCESS;
}

hyperdisk::returncode
hyperdisk :: shard :: sync()
{
    if (msync(m_data, FILE_SIZE, MS_SYNC) < 0)
    {
        return SYNCFAILED;
    }

    return SUCCESS;
}

e::intrusive_ptr<hyperdisk::shard_snapshot>
hyperdisk :: shard :: make_snapshot()
{
    e::intrusive_ptr<shard> d = this;
    assert(m_ref >= 2);
    e::intrusive_ptr<shard_snapshot> ret = new shard_snapshot(d);
    return ret;
}

hyperdisk :: shard :: shard(po6::io::fd* fd)
    : m_ref(0)
    , m_hash_table(NULL)
    , m_search_index(NULL)
    , m_data(NULL)
    , m_data_offset(INDEX_SEGMENT_SIZE)
    , m_search_offset(0)
{
    m_data = static_cast<char*>(mmap(NULL, FILE_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd->get(), 0));

    if (m_data == MAP_FAILED)
    {
        throw po6::error(errno);
    }

    m_hash_table = reinterpret_cast<uint64_t*>(m_data);
    m_search_index = reinterpret_cast<uint64_t*>(m_data + HASH_TABLE_SIZE);
}

hyperdisk :: shard :: ~shard()
                    throw ()
{
    munmap(m_data, FILE_SIZE);
}

size_t
hyperdisk :: shard :: data_size(const e::buffer& key,
                              const std::vector<e::buffer>& value) const
{
    size_t hypothetical_size = sizeof(uint64_t) + sizeof(uint32_t)
                             + sizeof(uint16_t) + key.size()
                             + sizeof(uint32_t) * value.size();

    for (size_t i = 0; i < value.size(); ++i)
    {
        hypothetical_size += value[i].size();
    }

    return hypothetical_size;
}

uint64_t
hyperdisk :: shard :: data_version(uint32_t offset) const
{
    assert(((offset + 7) & ~7) == offset);
    return *reinterpret_cast<uint64_t*>(m_data + offset);
}

size_t
hyperdisk :: shard :: data_key_size(uint32_t offset) const
{
    assert(((offset + 7) & ~7) == offset);
    return *reinterpret_cast<uint32_t*>(m_data + offset + sizeof(uint64_t));
}

void
hyperdisk :: shard :: data_key(uint32_t offset,
                             size_t keysize,
                             e::buffer* key) const
{
    assert(((offset + 7) & ~7) == offset);
    uint32_t cur_offset = offset + sizeof(uint64_t) + sizeof(uint32_t);
    *key = e::buffer(m_data + cur_offset, keysize);
}

void
hyperdisk :: shard :: data_value(uint32_t offset,
                               size_t keysize,
                               std::vector<e::buffer>* value) const
{
    assert(((offset + 7) & ~7) == offset);
    uint32_t cur_offset = offset + sizeof(uint64_t) + sizeof(uint32_t) + keysize;
    uint16_t num_dims;
    memmove(&num_dims, m_data + cur_offset, sizeof(uint16_t));
    cur_offset += sizeof(uint16_t);
    value->clear();

    for (uint16_t i = 0; i < num_dims; ++i)
    {
        uint32_t size;
        memmove(&size, m_data + cur_offset, sizeof(size));
        cur_offset += sizeof(size);
        value->push_back(e::buffer());
        e::buffer buf(m_data + cur_offset, size);
        value->back().swap(buf);
        cur_offset += size;
    }
}

bool
hyperdisk :: shard :: find_bucket(uint32_t primary_hash,
                                  const e::buffer& key,
                                  size_t* entry)
{
    // The first dead bucket.
    size_t dead = HASH_TABLE_ENTRIES;

    // The bucket/hash we want to use.
    *entry = HASH_INTO_TABLE(primary_hash);
    uint64_t expected = primary_hash;
    expected <<= 32;

    for (size_t off = 0; off < HASH_TABLE_ENTRIES; ++off)
    {
        size_t bucket = HASH_INTO_TABLE(*entry + off);
        const uint64_t hash_entry = m_hash_table[bucket];
        const uint64_t hash = hash_entry & ~uint64_t(OFFSETMASK);
        const uint32_t offset = hash_entry & OFFSETMASK;

        if (expected == hash && offset == OFFSETMASK)
        {
            dead = bucket;
        }
        else if (expected == hash)
        {
            const size_t key_size = data_key_size(offset);

            if (key_size == key.size() && memcmp(m_data + data_key_offset(offset), key.get(), key_size) == 0)
            {
                *entry = bucket;
                return true;
            }
        }

        if (offset == 0)
        {
            if (dead == HASH_TABLE_ENTRIES)
            {
                *entry = bucket;
            }
            else
            {
                *entry = dead;
            }

            return false;
        }

        if (offset == OFFSETMASK && dead == HASH_TABLE_ENTRIES)
        {
            dead = bucket;
        }
    }

    *entry = dead;
    return false;
}

void
hyperdisk :: shard :: invalidate_search_index(uint32_t to_invalidate, uint32_t invalidate_with)
{
    int64_t low = 0;
    int64_t high = SEARCH_INDEX_ENTRIES - 1;

    while (low <= high)
    {
        int64_t mid = low + ((high - low) / 2);
        const uint32_t mid_offset = m_search_index[mid * 2 + 1] & 0xffffffffUL;

        if (mid_offset == 0 || mid_offset > to_invalidate)
        {
            high = mid - 1;
        }
        else if (mid_offset < to_invalidate)
        {
            low = mid + 1;
        }
        else if (mid_offset == to_invalidate)
        {
            uint64_t new_entry = invalidate_with;
            new_entry <<= 32;
            new_entry |= to_invalidate;
            m_search_index[mid * 2 + 1] |= new_entry;
            return;
        }
    }
}
<|endoftext|>


<commit_before>#include "stdafx.h"
#include <stdio.h>
#include <conio.h>
#include <iostream>
#include <stdlib.h>
#include <time.h>
#include <string>
#include <windows.h>
#include "player.h"

using namespace std;

// Definicin de variables principales

	// Definicin de los parmetros del jugador y del enemigo
int enemylife = 410;
int enemymaxlife = 410;
int enemyattack = 18;
int enemytype = 1;

int playerlife = 460;
int playerattack = 21;
int playermagicattack = 18;
int playersp = 10;
int playermaxsp = 10;
int playermp = 16;
int playermaxmp = 16;

	// Defininicin de los valores que determinan la frecuencia y el poder de los ataques crticos
int subcriticalcheckerone;
int subcriticalcheckertwo;

int playercriticalchecker = 20;
int playercriticalpower;
float playercriticalmultiplier = 1.5;
int enemycriticalchecker = 20;
int enemycriticalpower = 36;

	// Cantidad de objetos que posee el jugador
int smallhealthpill = 2;
int smallhealthpillvalue = 100;
int damagepill = 2;

	// Efectos varios provocados por determinadas causas
bool damagepilleffect;
bool piercingeyeeffect;

	// Otros argumentos con funciones secundarias
bool battlechecker = true;
char movement;
int seed;
string playername;
int distanceenemy = 3;
bool successfulhit;
bool successfulhit2;
clock_t t;
bool runawayfrombattle;

	//Inicializacin de objetos
player mainplayer;

void clear(){
	HANDLE hndl = GetStdHandle(STD_OUTPUT_HANDLE);
	CONSOLE_SCREEN_BUFFER_INFO csbi;
	GetConsoleScreenBufferInfo(hndl, &csbi);
	DWORD written;
	DWORD n = csbi.dwSize.X * csbi.dwCursorPosition.Y + csbi.dwCursorPosition.X + 1;
	COORD curhome = {0,0};
	FillConsoleOutputCharacter(hndl, ' ', n, curhome, &written);
	csbi.srWindow.Bottom -= csbi.srWindow.Top;
	csbi.srWindow.Top = 0;
	SetConsoleWindowInfo(hndl, TRUE, &csbi.srWindow);
	SetConsoleCursorPosition(hndl, curhome);
}

void defeat(){
	if(playerlife <= 0){
		clear();
		cout << playername;
		cout << " has lost!\a" << endl;
		battlechecker = false;
		_getch();
		exit(0);
	}
}

void victory(){
	if(enemylife <= 0){
		clear();
		cout << playername;
		cout << " won the battle!\a" << endl;
		battlechecker = false;
		_getch();
		exit(0);
	}
}

void escapebattle(){
	if(runawayfrombattle == true){
		clear();
		cout << playername;
		cout << " ran away!\a" << endl;
		battlechecker = false;
		_getch();
		exit(0);
	}
}

void itemmenu(){
	printf("You have %d Small Health Pill(s) (+100 life)\n",smallhealthpill);
	printf("You have %d Damage Pill(s) (+10 attack until the end of the battle)\n",damagepill);
	printf("\nType 's' to use a Small Health Pill\n");
	printf("Type 'd' to use a Damage Pill\n");
	printf("Type any other key to go back to the main menu and skip the turn\n");
	cin >> movement;
	clear();
	switch(movement){
	case 's' :
		if(smallhealthpill > 0){
			smallhealthpill--;
			playerlife += smallhealthpillvalue;
			if(playerlife >= playermaxlifeclone){
				playerlife = playermaxlifeclone;
			}
			printf("Used a Small Health Pill and life was restored by 50 points! %d remaining\n",smallhealthpill);
			}
		else{
			printf("You haven't any Small Health Pills left!\n");
		}
		break;
	case 'd' :
		if(damagepill > 0){
			damagepill--;
			damagepilleffect = true;
			printf("Used a Damage Pill and attack was increased by 10 points! %d remaining\n",damagepill);
		}
		else{
			cout << "You haven't any Damage Pills left!" << endl;
		}
		break;
	default : cout << "Closed the item bag without using items" << endl;
	}
}

void battlemenu(){
	cout << "Grass Common Bandit" << endl;
	if(piercingeyeeffect == false){
		printf("Life = %d\n",enemylife);
	}
	else{
		printf("Life = %d/%d\n",enemylife,enemymaxlife);
		printf("Attack = %d\n",enemyattack);
	}
	if(piercingeyeeffect == true){
		cout << "Weak to: ";
		if(enemytype == 1){
			cout << "Fire (x2)" << endl;
		}
		else{
			clear();
			cout << "CRITICAL ERROR: 'ENEMY TYPE CORRUPT'" << endl;
			_getch();
			exit(1);
		}
		cout << "Resistant to: ";
		if(enemytype == 1){
			cout << "Nothing" << endl;
		}
		else{
			clear();
			cout << "CRITICAL ERROR: 'ENEMY TYPE CORRUPT'" << endl;
			_getch();
			exit(1);
		}
	}
	printf("Effects = ");
	if(piercingeyeeffect == true){
		cout << "Piercing Eye (Infinite turns remaining)\n" << endl;
	}
	if(piercingeyeeffect == false){
		cout << "None\n" << endl;
	}
	cout << playername;
    printf("'s life = %d/",playerlife);
	mainplayer.saymaxlife();
	cout << endl;
	cout << playername;
    printf("'s SP = %d/%d\n",playersp,playermaxsp);
	cout << playername;
    printf("'s MP = %d/%d\n",playermp,playermaxmp);
	cout << playername;
	printf("'s attack");
	if(damagepilleffect == true){
		printf(" = %d (Damage Pill +10 attack)\n",playerattack + 10);
	}
	if(damagepilleffect == false){
		printf(" = %d\n",playerattack);
	}
	cout << playername;
	printf("'s magic attack = %d\n",playermagicattack);
	printf("Distance from the enemy: ");
	if(distanceenemy == 1){
		cout << "Very short" << endl;
	}
	if(distanceenemy == 2){
		cout << "Short" << endl;
	}
	if(distanceenemy == 3){
		cout << "Medium" << endl;
	}
	if(distanceenemy == 4){
		cout << "Far" << endl;
	}
	if(distanceenemy == 5){
		cout << "Very far" << endl;
	}
	printf("\nType '1' to attack the enemy\n");
	printf("Type '2' to open the item bag\n");
	printf("Type '3' to show the special moves list\n");
	printf("Type '4' to show the magic learned\n");
	printf("Type '5' to get closer to the enemy\n");
	if(distanceenemy == 5){
		printf("Type '6' to run away from the battle\n");
	}
	else{
		printf("Type '6' to move away from the enemy\n");
	}
	printf("Type any other key to skip the turn\n");
}

void battle(){
	while(battlechecker == true){

		STARTBATTLE:

		if(damagepilleffect == false){
			playercriticalpower = (playerattack * playercriticalmultiplier);
		}
		else{
			playercriticalpower = ((playerattack * playercriticalmultiplier) + 10);
		}

		t = clock();
		if(t >= 10000){
			t-=9999;
		}
		srand(seed);

		// Comprueba si has ganado o perdido la batalla
		escapebattle();
		victory();
		defeat();

		// Muestra el men con parte de los parmetros y sus explicaciones, junto con las acciones que puede hacer el jugador
		battlemenu();

		// Comprueba si la distancia frente al enemigo es lo suficientemente corta como para realizar un ataque fsico
		if(distanceenemy == 1 || distanceenemy == 2){
			successfulhit = true;
			successfulhit2 = true;
		}
		if(distanceenemy == 3 || distanceenemy == 4 || distanceenemy == 5){
			successfulhit = false;
			successfulhit2 = false;
		}

		// Se ejecuta el turno del jugador
		cin >> movement;
		clear();

		switch(movement){
		case '1':
			seed = t;
			subcriticalcheckerone = rand() % 100;
			if(successfulhit == true){
				if(damagepilleffect == false){
					if(subcriticalcheckerone <= playercriticalchecker){
						cout << "\a";
						enemylife -= playercriticalpower;
						cout << playername;
						printf(" made a critical hit, causing %d damage!\n",playercriticalpower);
					}
					else{
						enemylife -= playerattack;
						cout << playername;
						printf(" inflicted %d damage to the enemy\n",playerattack);
					}
				}
				if(damagepilleffect == true){
					if(subcriticalcheckerone <= playercriticalchecker){
						cout << "\a";
						enemylife -= (playercriticalpower + 10);
						cout << playername;
						printf(" made a critical hit, causing %d damage!\n",playercriticalpower);
					}
					else{
						enemylife -= (playerattack + 10);
						cout << playername;
						printf(" inflicted %d damage to the enemy\n",playerattack + 10);
					}
				}
			}
			else{
				cout << "You are too far from the enemy to perform that move!" << endl;
			}
			break;
		case '2':
			itemmenu();break;
		case '3':
			printf("List of Special moves:\n\n");
			printf("Piercing eye [2 SP]['1' to use]\n");
			printf("-- Unveils more detailed stats of the enemy\n");
			printf("Quick eye [5 SP]['2' to use]\n");
			printf("-- Unveils more detailed stats of the enemy without finishing the current turn\n");
			printf("\nType any other key to go back to the main menu\n");
			cin >> movement;
			clear();
			switch(movement){
			case '1' :
				if(playersp >= 2){
					playersp--;
					playersp--;
					piercingeyeeffect = true;
					cout << "Used Piercing Eye!" << endl;
				}
				else{
					cout << "You haven't enough SP left to perform this move!" << endl;
				}
				break;
			case '2' :
				if(playersp >= 5){
					playersp = (playersp - 5);
					piercingeyeeffect = true;
					cout << "Used Quick Eye!\n" << endl;
					goto STARTBATTLE;
					break;
				}
				else{
					cout << "You haven't enough SP left to perform this move!" << endl;
				}
				break;
			default : goto STARTBATTLE;
				}
			break;
		case '5' :
			if(distanceenemy == 1){
				cout << "You can't get closer to the enemy!" << endl;
			}
			else{
				distanceenemy--;
				cout << "Got closer to the enemy" << endl;
			}
			break;
		case '6' :
			if(distanceenemy == 5){
				runawayfrombattle = true;
				goto STARTBATTLE;
			}
			else{
				distanceenemy++;
				cout << "Moved a bit away from the enemy" << endl;
			}
			break;
		case '4' :
			printf("List of Magic learned:\n\n");
			printf("Meditate [6 MP]['1' to use]\n");
			printf("-- Heals the player by 60 life points\n");
			printf("Fire [4 MP]['2' to use]\n");
			printf("-- Harms the enemy using the Fire Element\n");
			printf("\nType any other key to go back to the main menu\n");
			cin >> movement;
			clear();
			switch(movement){
			case '1' :
				if(playermp >= 6){
					playermp -= 6;
					playerlife += 60;
					if(playerlife >= playermaxlifeclone){
						playerlife = playermaxlifeclone;
					}
					cout << "Used Meditate and life was restored by 60 points!" << endl;
				}
				else{
					cout << "You haven't enough MP left to perform this move!" << endl;
				}
				break;
			case '2' :
				if(playermp >= 4){
					playermp -= 4;
					if(enemytype == 1){
						enemylife = (enemylife - playermagicattack * 2);
						printf("You dealt %d damage to the enemy by using Fire! It was very effective!\n",playermagicattack * 2);
					}
					else{
						enemylife -= playermagicattack;
						printf("You dealt %d damage to the enemy by using Fire!\n",playermagicattack);
					}
				}
				else{
					cout << "You haven't enough MP left to perform this move!" << endl;
				}
				break;
			default :
				goto STARTBATTLE;
			}
			break;

		default: cout << "Skipped the turn" << endl;break;
		}

		// Comprueba de nuevo si la distancia frente al enemigo es lo suficientemente corta como para realizar un ataque fsico
		if(distanceenemy == 1 || distanceenemy == 2){
			successfulhit = true;
			successfulhit2 = true;
		}
		if(distanceenemy == 3 || distanceenemy == 4 || distanceenemy == 5){
			successfulhit = false;
			successfulhit2 = false;
		}

		 // El enemigo ejecuta su turno
		seed = t;
		subcriticalcheckertwo = rand() % 100;
		if(successfulhit2 == true){
			if(subcriticalcheckertwo <= enemycriticalchecker){
				playerlife -= enemycriticalpower;
				printf("The enemy made a critical hit!\n\n");
			}
			else{
				playerlife -= enemyattack;
				printf("The enemy inflicted %d damage\n\n",enemyattack);
			}
		}
		else{
			cout << "The enemy got closer to " << playername << endl << endl;
			distanceenemy--;
		}
	}
}

int main(){
	// Inicio del programa, se le pregunta al jugador el nombre del main character
	while(1){
		cout << "Welcome to CutreRPG Alpha 0.3.4.2!" << endl;
		cout << "What will be the main character's name?" << endl;
		cin >> playername;
		clear();
		if(playername == "Trackpoth"){
			cout << "Will it be our god and savior's name, Trackpoth?\n\a" << endl;
		}
		if(playername == "COCOS"){
			cout << "COCOS\aCOCOS\aCOCOS\aCOCOS\aCOCOS\aCOCOS\aCOCOS\aCOCOS\aCOCOS\aCOCOS\aCOCOS\aCOCOS\aCOCOS\aCOCOS\aCOCOS\a\n" << endl;
		}
		if(playername != "Trackpoth"){
			if(playername != "COCOS"){
				cout << "Will it be ";
				cout << playername;
				cout << "?\a\n\n";
			}
		}
		cout << "Type '1' to say yes" << endl;
		cout << "Type any other key to input a different name" << endl;
		cin >> movement;
		switch (movement){
		case '1' :
			clear();
			cout << "Name applied correctly" << endl;
			printf("You found an enemy!\n\n");
			battle();
			break;
		}
		clear();
	}
	return 0;
}<commit_msg>Fixed bugs<commit_after>#include "stdafx.h"
#include <stdio.h>
#include <conio.h>
#include <iostream>
#include <stdlib.h>
#include <time.h>
#include <string>
#include <windows.h>
#include "player.h"

using namespace std;

	//Inicializacin de objetos
player mainplayer;

void clear(){
	HANDLE hndl = GetStdHandle(STD_OUTPUT_HANDLE);
	CONSOLE_SCREEN_BUFFER_INFO csbi;
	GetConsoleScreenBufferInfo(hndl, &csbi);
	DWORD written;
	DWORD n = csbi.dwSize.X * csbi.dwCursorPosition.Y + csbi.dwCursorPosition.X + 1;
	COORD curhome = {0,0};
	FillConsoleOutputCharacter(hndl, ' ', n, curhome, &written);
	csbi.srWindow.Bottom -= csbi.srWindow.Top;
	csbi.srWindow.Top = 0;
	SetConsoleWindowInfo(hndl, TRUE, &csbi.srWindow);
	SetConsoleCursorPosition(hndl, curhome);
}

void defeat(){
	if(playerlife <= 0){
		clear();
		cout << playername;
		cout << " has lost!\a" << endl;
		battlechecker = false;
		_getch();
		exit(0);
	}
}

void victory(){
	if(enemylife <= 0){
		clear();
		cout << playername;
		cout << " won the battle!\a" << endl;
		battlechecker = false;
		_getch();
		exit(0);
	}
}

void escapebattle(){
	if(runawayfrombattle == true){
		clear();
		cout << playername;
		cout << " ran away!\a" << endl;
		battlechecker = false;
		_getch();
		exit(0);
	}
}

void itemmenu(){
	printf("You have %d Small Health Pill(s) (+%d life)\n",smallhealthpill,smallhealthpillvalue);
	printf("You have %d Damage Pill(s) (+10 attack until the end of the battle)\n",damagepill);
	printf("\nType '1' to use a Small Health Pill\n");
	printf("Type '2' to use a Damage Pill\n");
	printf("Type any other key to go back to the main menu and skip the turn\n");
	cin >> movement;
	clear();
	switch(movement){
	case '1' :
		if(smallhealthpill > 0){
			smallhealthpill--;
			playerlife += smallhealthpillvalue;
			mainplayer.limitplayerlife();
			printf("Used a Small Health Pill and life was restored by %d points! %d remaining\n",smallhealthpillvalue,smallhealthpill);
		}
		else{
			printf("You haven't any Small Health Pills left!\n");
		}
		break;
	case '2' :
		if(damagepill > 0){
			damagepill--;
			damagepilleffect = true;
			printf("Used a Damage Pill and attack was increased by 10 points! %d remaining\n",damagepill);
		}
		else{
			cout << "You haven't any Damage Pills left!" << endl;
		}
		break;
	default : cout << "Closed the item bag without using items" << endl;
	}
}

void battlemenu(){
	cout << "Grass Common Bandit" << endl;
	if(piercingeyeeffect == false){
		printf("Life = %d\n",enemylife);
	}
	else{
		printf("Life = %d/%d\n",enemylife,enemymaxlife);
		printf("Attack = %d\n",enemyattack);
	}
	if(piercingeyeeffect == true){
		cout << "Weak to: ";
		if(enemytype == 1){
			cout << "Fire (x2)" << endl;
		}
		else{
			clear();
			cout << "CRITICAL ERROR: 'ENEMY TYPE CORRUPT'" << endl;
			_getch();
			exit(1);
		}
		cout << "Resistant to: ";
		if(enemytype == 1){
			cout << "Nothing" << endl;
		}
		else{
			clear();
			cout << "CRITICAL ERROR: 'ENEMY TYPE CORRUPT'" << endl;
			_getch();
			exit(1);
		}
	}
	printf("Effects = ");
	if(piercingeyeeffect == true){
		cout << "Piercing Eye (Infinite turns remaining)\n" << endl;
	}
	if(piercingeyeeffect == false){
		cout << "None\n" << endl;
	}
	cout << playername;
    printf("'s life = %d/",playerlife);
	mainplayer.saymaxlife();
	cout << endl;
	cout << playername;
    printf("'s SP = %d/%d\n",playersp,playermaxsp);
	cout << playername;
    printf("'s MP = %d/%d\n",playermp,playermaxmp);
	cout << playername;
	printf("'s attack");
	if(damagepilleffect == true){
		cout << " = ";
		mainplayer.sayattack();
		cout << " (Damage Pill +10 attack)" << endl;
	}
	if(damagepilleffect == false){
		cout << " = ";
		mainplayer.sayattack();
		cout << endl;
	}
	cout << playername;
	printf("'s magic attack = %d\n",playermagicattack);
	printf("Distance from the enemy: ");
	if(distanceenemy == 1){
		cout << "Very short" << endl;
	}
	if(distanceenemy == 2){
		cout << "Short" << endl;
	}
	if(distanceenemy == 3){
		cout << "Medium" << endl;
	}
	if(distanceenemy == 4){
		cout << "Far" << endl;
	}
	if(distanceenemy == 5){
		cout << "Very far" << endl;
	}
	printf("\nType '1' to attack the enemy\n");
	printf("Type '2' to open the item bag\n");
	printf("Type '3' to show the special moves list\n");
	printf("Type '4' to show the magic learned\n");
	printf("Type '5' to get closer to the enemy\n");
	if(distanceenemy == 5){
		printf("Type '6' to run away from the battle\n");
	}
	else{
		printf("Type '6' to move away from the enemy\n");
	}
	printf("Type any other key to skip the turn\n");
}

void battle(){
	while(battlechecker == true){

		STARTBATTLE:

		mainplayer.determinecriticalpower();

		t = clock();
		if(t >= 10000){
			t-=9999;
		}
		srand(seed);

		// Comprueba si has ganado o perdido la batalla
		escapebattle();
		victory();
		defeat();

		// Muestra el men con parte de los parmetros y sus explicaciones, junto con las acciones que puede hacer el jugador
		battlemenu();

		// Comprueba si la distancia frente al enemigo es lo suficientemente corta como para realizar un ataque fsico
		if(distanceenemy == 1 || distanceenemy == 2){
			successfulhit = true;
			successfulhit2 = true;
		}
		if(distanceenemy == 3 || distanceenemy == 4 || distanceenemy == 5){
			successfulhit = false;
			successfulhit2 = false;
		}

		// Se ejecuta el turno del jugador
		cin >> movement;
		clear();

		switch(movement){
		case '1':
			seed = t;
			subcriticalcheckerone = rand() % 100;
			if(successfulhit == true){
				mainplayer.attackenemy();
			}
			else{
				cout << "You are too far from the enemy to perform that move!" << endl;
			}
			break;
		case '2':
			itemmenu();break;
		case '3':
			printf("List of Special moves:\n\n");
			printf("Piercing eye [2 SP]['1' to use]\n");
			printf("-- Unveils more detailed stats of the enemy\n");
			printf("Quick eye [5 SP]['2' to use]\n");
			printf("-- Unveils more detailed stats of the enemy without finishing the current turn\n");
			printf("\nType any other key to go back to the main menu\n");
			cin >> movement;
			clear();
			switch(movement){
			case '1' :
				if(playersp >= 2){
					playersp--;
					playersp--;
					piercingeyeeffect = true;
					cout << "Used Piercing Eye!" << endl;
				}
				else{
					cout << "You haven't enough SP left to perform this move!" << endl;
				}
				break;
			case '2' :
				if(playersp >= 5){
					playersp = (playersp - 5);
					piercingeyeeffect = true;
					cout << "Used Quick Eye!\n" << endl;
					goto STARTBATTLE;
					break;
				}
				else{
					cout << "You haven't enough SP left to perform this move!" << endl;
				}
				break;
			default : goto STARTBATTLE;
				}
			break;
		case '5' :
			if(distanceenemy == 1){
				cout << "You can't get closer to the enemy!" << endl;
			}
			else{
				distanceenemy--;
				cout << "Got closer to the enemy" << endl;
			}
			break;
		case '6' :
			if(distanceenemy == 5){
				runawayfrombattle = true;
				goto STARTBATTLE;
			}
			else{
				distanceenemy++;
				cout << "Moved a bit away from the enemy" << endl;
			}
			break;
		case '4' :
			printf("List of Magic learned:\n\n");
			printf("Meditate [6 MP]['1' to use]\n");
			printf("-- Heals the player by 60 life points\n");
			printf("Fire [4 MP]['2' to use]\n");
			printf("-- Harms the enemy using the Fire Element\n");
			printf("\nType any other key to go back to the main menu\n");
			cin >> movement;
			clear();
			switch(movement){
			case '1' :
				if(playermp >= 6){
					playermp -= 6;
					playerlife += 60;
					mainplayer.limitplayerlife();
					cout << "Used Meditate and life was restored by 60 points!" << endl;
				}
				else{
					cout << "You haven't enough MP left to perform this move!" << endl;
				}
				break;
			case '2' :
				if(playermp >= 4){
					playermp -= 4;
					if(enemytype == 1){
						enemylife = (enemylife - playermagicattack * 2);
						printf("You dealt %d damage to the enemy by using Fire! It was very effective!\n",playermagicattack * 2);
					}
					else{
						enemylife -= playermagicattack;
						printf("You dealt %d damage to the enemy by using Fire!\n",playermagicattack);
					}
				}
				else{
					cout << "You haven't enough MP left to perform this move!" << endl;
				}
				break;
			default :
				goto STARTBATTLE;
			}
			break;

		default: cout << "Skipped the turn" << endl;break;
		}

		// Comprueba de nuevo si la distancia frente al enemigo es lo suficientemente corta como para realizar un ataque fsico
		if(distanceenemy == 1 || distanceenemy == 2){
			successfulhit = true;
			successfulhit2 = true;
		}
		if(distanceenemy == 3 || distanceenemy == 4 || distanceenemy == 5){
			successfulhit = false;
			successfulhit2 = false;
		}

		 // El enemigo ejecuta su turno
		seed = t;
		subcriticalcheckertwo = rand() % 100;
		if(successfulhit2 == true){
			if(subcriticalcheckertwo <= enemycriticalchecker){
				playerlife -= enemycriticalpower;
				printf("The enemy made a critical hit!\n\n");
			}
			else{
				playerlife -= enemyattack;
				printf("The enemy inflicted %d damage\n\n",enemyattack);
			}
		}
		else{
			cout << "The enemy got closer to " << playername << endl << endl;
			distanceenemy--;
		}
	}
}

int main(){
	// Inicio del programa, se le pregunta al jugador el nombre del main character
	while(1){
		cout << "Welcome to CutreRPG Alpha 0.3.4.3!" << endl;
		cout << "What will be the main character's name?" << endl;
		cin >> playername;
		clear();
		if(playername == "Trackpoth"){
			cout << "Will it be our god and savior's name, Trackpoth?\n\a" << endl;
		}
		if(playername == "COCOS"){
			cout << "COCOS\aCOCOS\aCOCOS\aCOCOS\aCOCOS\aCOCOS\aCOCOS\aCOCOS\aCOCOS\aCOCOS\aCOCOS\aCOCOS\aCOCOS\aCOCOS\aCOCOS\a\n" << endl;
		}
		if(playername != "Trackpoth"){
			if(playername != "COCOS"){
				cout << "Will it be ";
				cout << playername;
				cout << "?\a\n\n";
			}
		}
		cout << "Type '1' to say yes" << endl;
		cout << "Type any other key to input a different name" << endl;
		cin >> movement;
		switch (movement){
		case '1' :
			clear();
			cout << "Name applied correctly" << endl;
			printf("You found an enemy!\n\n");
			battle();
			break;
		}
		clear();
	}
	return 0;
}<|endoftext|>