<commit_before>/**
 * Scintilla source code edit control
 * @file LexMySQL.cxx
 * Lexer for MySQL
 *
 * Improved by Mike Lischke <mike.lischke@sun.com>
 * Adopted from LexSQL.cxx by Anders Karlsson <anders@mysql.com>
 * Original work by Neil Hodgson <neilh@scintilla.org>
 * Copyright 1998-2005 by Neil Hodgson <neilh@scintilla.org>
 * The License.txt file describes the conditions under which this software may be distributed.
 */

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

#include "Platform.h"

#include "PropSet.h"
#include "Accessor.h"
#include "StyleContext.h"
#include "KeyWords.h"
#include "Scintilla.h"
#include "SciLexer.h"

#ifdef SCI_NAMESPACE
using namespace Scintilla;
#endif

static inline bool IsAWordChar(int ch) {
	return (ch < 0x80) && (isalnum(ch) || ch == '_');
}

static inline bool IsAWordStart(int ch) {
	return (ch < 0x80) && (isalpha(ch) || ch == '_');
}

static inline bool IsADoxygenChar(int ch) {
	return (islower(ch) || ch == '$' || ch == '@' ||
	        ch == '\\' || ch == '&' || ch == '<' ||
	        ch == '>' || ch == '#' || ch == '{' ||
	        ch == '}' || ch == '[' || ch == ']');
}

static inline bool IsANumberChar(int ch) {
	// Not exactly following number definition (several dots are seen as OK, etc.)
	// but probably enough in most cases.
	return (ch < 0x80) &&
	        (isdigit(ch) || toupper(ch) == 'E' ||
             ch == '.' || ch == '-' || ch == '+');
}

//--------------------------------------------------------------------------------------------------

/**
 * Check if the current content context represent a keyword and set the context state if so.
 */
static void CheckForKeyword(StyleContext& sc, WordList* keywordlists[])
{
  int length = sc.LengthCurrent() + 1; // +1 for the next char
  char* s = new char[length];
  sc.GetCurrentLowered(s, length);
  if (keywordlists[0]->InList(s))
    sc.ChangeState(SCE_MYSQL_MAJORKEYWORD);
  else
    if (keywordlists[1]->InList(s))
      sc.ChangeState(SCE_MYSQL_KEYWORD);
    else
      if (keywordlists[2]->InList(s))
        sc.ChangeState(SCE_MYSQL_DATABASEOBJECT);
      else
        if (keywordlists[3]->InList(s))
          sc.ChangeState(SCE_MYSQL_FUNCTION);
        else
          if (keywordlists[5]->InList(s))
            sc.ChangeState(SCE_MYSQL_PROCEDUREKEYWORD);
          else
            if (keywordlists[6]->InList(s))
              sc.ChangeState(SCE_MYSQL_USER1);
            else
              if (keywordlists[7]->InList(s))
                sc.ChangeState(SCE_MYSQL_USER2);
              else
                if (keywordlists[8]->InList(s))
                  sc.ChangeState(SCE_MYSQL_USER3);
  delete [] s;
}

//--------------------------------------------------------------------------------------------------

static void ColouriseMySQLDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[],
                            Accessor &styler)
{
	StyleContext sc(startPos, length, initStyle, styler);

	for (; sc.More(); sc.Forward())
  {
		// Determine if the current state should terminate.
		switch (sc.state)
    {
      case SCE_MYSQL_OPERATOR:
        sc.SetState(SCE_MYSQL_DEFAULT);
        break;
      case SCE_MYSQL_NUMBER:
        // We stop the number definition on non-numerical non-dot non-eE non-sign char.
        if (!IsANumberChar(sc.ch))
          sc.SetState(SCE_MYSQL_DEFAULT);
        break;
      case SCE_MYSQL_IDENTIFIER:
        // Switch from identifier to keyword state and open a new state for the new char.
        if (!IsAWordChar(sc.ch))
        {
          CheckForKeyword(sc, keywordlists);
          sc.SetState(SCE_MYSQL_DEFAULT);
        }
        break;
      case SCE_MYSQL_VARIABLE:
        if (!IsAWordChar(sc.ch))
          sc.SetState(SCE_MYSQL_DEFAULT);
        break;
      case SCE_MYSQL_SYSTEMVARIABLE:
        if (!IsAWordChar(sc.ch))
        {
          int length = sc.LengthCurrent() + 1;
          char* s = new char[length];
          sc.GetCurrentLowered(s, length);

          // Check for known system variables here.
          if (keywordlists[4]->InList(&s[2]))
            sc.ChangeState(SCE_MYSQL_KNOWNSYSTEMVARIABLE);
          delete [] s;

          sc.SetState(SCE_MYSQL_DEFAULT);
        }
        break;
      case SCE_MYSQL_QUOTEDIDENTIFIER:
        if (sc.ch == '`')
        {
          if (sc.chNext == '`')
            sc.Forward();	// Ignore it
          else
            sc.ForwardSetState(SCE_MYSQL_DEFAULT);
				}
  			break;
      case SCE_MYSQL_COMMENT:
      case SCE_MYSQL_HIDDENCOMMAND:
        if (sc.Match('*', '/'))
        {
          sc.Forward();
          sc.ForwardSetState(SCE_MYSQL_DEFAULT);
        }
        break;
      case SCE_MYSQL_COMMENTLINE:
        if (sc.atLineStart)
          sc.SetState(SCE_MYSQL_DEFAULT);
        break;
      case SCE_MYSQL_SQSTRING:
        if (sc.ch == '\\')
          sc.Forward(); // Escape sequence
        else
          if (sc.ch == '\'')
          {
            // End of single quoted string reached?
            if (sc.chNext == '\'')
              sc.Forward();
            else
              sc.ForwardSetState(SCE_MYSQL_DEFAULT);
          }
        break;
      case SCE_MYSQL_DQSTRING:
        if (sc.ch == '\\')
          sc.Forward(); // Escape sequence
        else
          if (sc.ch == '\"')
          {
            // End of single quoted string reached?
            if (sc.chNext == '\"')
              sc.Forward();
            else
              sc.ForwardSetState(SCE_MYSQL_DEFAULT);
          }
        break;
    }

    // Determine if a new state should be entered.
    if (sc.state == SCE_MYSQL_DEFAULT)
    {
      switch (sc.ch)
      {
        case '@':
          if (sc.chNext == '@')
          {
            sc.SetState(SCE_MYSQL_SYSTEMVARIABLE);
            sc.Forward(2); // Skip past @@.
          }
          else
            if (IsAWordStart(sc.ch))
            {
              sc.SetState(SCE_MYSQL_VARIABLE);
              sc.Forward(); // Skip past @.
            }
            else
              sc.SetState(SCE_MYSQL_OPERATOR);
          break;
        case '`':
          sc.SetState(SCE_MYSQL_QUOTEDIDENTIFIER);
          break;
        case '#':
          sc.SetState(SCE_MYSQL_COMMENTLINE);
          break;
        case '\'':
          sc.SetState(SCE_MYSQL_SQSTRING);
          break;
        case '\"':
          sc.SetState(SCE_MYSQL_DQSTRING);
          break;
        default:
          if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext)))
            sc.SetState(SCE_MYSQL_NUMBER);
          else
            if (IsAWordStart(sc.ch))
              sc.SetState(SCE_MYSQL_IDENTIFIER);
            else
              if (sc.Match('/', '*'))
              {
                sc.SetState(SCE_MYSQL_COMMENT);

                // Skip comment introducer and check for hidden command.
                sc.Forward(2);
                if (sc.ch == '!')
                {
                  sc.ChangeState(SCE_MYSQL_HIDDENCOMMAND);
                  sc.Forward();
                }
              }
              else
                if (sc.Match("--"))
                {
                  // Special MySQL single line comment.
                  sc.SetState(SCE_MYSQL_COMMENTLINE);
                  sc.Forward(2);

                  // Check the third character too. It must be a space or EOL.
                  if (sc.ch != ' ' && sc.ch != '\n' && sc.ch != '\r')
                    sc.ChangeState(SCE_MYSQL_OPERATOR);
                }
                else
                  if (isoperator(static_cast<char>(sc.ch)))
                    sc.SetState(SCE_MYSQL_OPERATOR);
      }
    }
  }

  // Do a final check for keywords if we currently have an identifier, to highlight them
  // also at the end of a line.
  if (sc.state == SCE_MYSQL_IDENTIFIER)
    CheckForKeyword(sc, keywordlists);

  sc.Complete();
}

//--------------------------------------------------------------------------------------------------

/**
 * Helper function to determine if we have a foldable comment currently.
 */
static bool IsStreamCommentStyle(int style)
{
	return style == SCE_MYSQL_COMMENT;
}

//--------------------------------------------------------------------------------------------------

// Store both the current line's fold level and the next lines in the
// level store to make it easy to pick up with each increment.
static void FoldMySQLDoc(unsigned int startPos, int length, int initStyle, WordList *[], Accessor &styler)
{
	bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
	bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
	bool foldOnlyBegin = styler.GetPropertyInt("fold.sql.only.begin", 0) != 0;

  StyleContext sc(startPos, length, initStyle, styler);

	int visibleChars = 0;
	int lineCurrent = styler.GetLine(startPos);
	int levelCurrent = SC_FOLDLEVELBASE;
	if (lineCurrent > 0)
		levelCurrent = styler.LevelAt(lineCurrent - 1) >> 16;
	int levelNext = levelCurrent;

	int styleNext = styler.StyleAt(startPos);
	int style = initStyle;

  bool endFound = false;
	bool whenFound = false;
	bool elseFound = false;

  for (unsigned int i = startPos; sc.More(); i++, sc.Forward())
  {
		int stylePrev = style;
		style = styleNext;
		styleNext = styler.StyleAt(i + 1);
		bool atEOL = (sc.ch == '\r' && sc.chNext != '\n') || (sc.ch == '\n');

    switch (style)
    {
      case SCE_MYSQL_COMMENT:
        if (foldComment)
        {
          // Multiline comment style /* .. */.
          if (IsStreamCommentStyle(style))
          {
            // Increase level if we just start a foldable comment.
            if (!IsStreamCommentStyle(stylePrev))
              levelNext++;
            else
              // If we are in the middle of a foldable comment check if it ends now.
              // Don't end at the line end, though.
              if (!IsStreamCommentStyle(styleNext) && !atEOL)
                levelNext--;
          }
        }
        break;
      case SCE_MYSQL_COMMENTLINE:
        if (foldComment)
        {
          // Not really a standard, but we add support for single line comments
          // with special curly braces syntax as foldable comments too.
          // MySQL needs -- comments to be followed by space or control char
          if (sc.Match('-', '-'))
          {
            char chNext2 = styler.SafeGetCharAt(i + 2);
            char chNext3 = styler.SafeGetCharAt(i + 3);
            if (chNext2 == '{' || chNext3 == '{')
              levelNext++;
            else
              if (chNext2 == '}' || chNext3 == '}')
                levelNext--;
          }
        }
        break;
      case SCE_MYSQL_HIDDENCOMMAND:
        if (style != stylePrev)
          levelNext++;
        else
          if (style != styleNext)
            levelNext--;
        break;
      case SCE_MYSQL_OPERATOR:
        if (sc.ch == '(')
          levelNext++;
        else
          if (sc.ch == ')')
            levelNext--;
        break;
      case SCE_MYSQL_MAJORKEYWORD:
      case SCE_MYSQL_KEYWORD:
      case SCE_MYSQL_FUNCTION:
      case SCE_MYSQL_PROCEDUREKEYWORD:
        // Reserved and other keywords.
        if (style != stylePrev)
        {
          bool beginFound = sc.MatchIgnoreCase("begin");
          bool ifFound = sc.MatchIgnoreCase("if");
          bool thenFound = sc.MatchIgnoreCase("then");
          bool whileFound = sc.MatchIgnoreCase("while");
          bool loopFound = sc.MatchIgnoreCase("loop");
          bool repeatFound = sc.MatchIgnoreCase("repeat");

          if (!foldOnlyBegin && endFound && (ifFound || whileFound || loopFound))
          {
            endFound = false;
            levelNext--;
            if (levelNext < SC_FOLDLEVELBASE)
              levelNext = SC_FOLDLEVELBASE;

            // Note that "else" is special here. It may or may not be followed by an "if .. then",
            // but in any case the level stays the same. When followed by an "if .. then" the level
            // will be increased later, if not, then at eol.
          }
          else
            if (!foldOnlyBegin && sc.MatchIgnoreCase("else"))
            {
              levelNext--;
              elseFound = true;
            }
            else
              if (!foldOnlyBegin && thenFound)
              {
                if (whenFound)
                  whenFound = false;
                else
                  levelNext++;
              }
              else
                if (ifFound)
                  elseFound = false;
                else
                  if (sc.MatchIgnoreCase("when"))
                    whenFound = true;
                  else
                  {
                    if (beginFound)
                      levelNext++;
                    else
                      if (!foldOnlyBegin && (loopFound || repeatFound || whileFound))
                      {
                        if (endFound)
                          endFound = false;
                        else
                          levelNext++;
                      }
                      else
                        if (sc.MatchIgnoreCase("end"))
                        {
                          // Multiple "end" in a row are counted multiple times!
                          if (endFound)
                          {
                            levelNext--;
                            if (levelNext < SC_FOLDLEVELBASE)
                              levelNext = SC_FOLDLEVELBASE;
                          }
                          endFound = true;
                          whenFound = false;
                        }
                  }
        }
        break;
    }

    // Handle the case of a trailing end without an if / while etc, as in the case of a begin.
		if (endFound)
    {
			endFound = false;
			levelNext--;
			if (levelNext < SC_FOLDLEVELBASE)
        levelNext = SC_FOLDLEVELBASE;
		}

		if (atEOL)
    {
			if (elseFound)
      {
				levelNext++;
        elseFound = false;
      }

			int levelUse = levelCurrent;
			int lev = levelUse | levelNext << 16;
			if (visibleChars == 0 && foldCompact)
				lev |= SC_FOLDLEVELWHITEFLAG;
			if (levelUse < levelNext)
				lev |= SC_FOLDLEVELHEADERFLAG;
			if (lev != styler.LevelAt(lineCurrent))
				styler.SetLevel(lineCurrent, lev);

			lineCurrent++;
			levelCurrent = levelNext;
			visibleChars = 0;
			endFound = false;
			whenFound = false;
		}

		if (!isspacechar(static_cast<char>(sc.ch)))
			visibleChars++;
	}
}

//--------------------------------------------------------------------------------------------------

static const char * const mysqlWordListDesc[] = {
	"Major Keywords",
	"Keywords",
	"Database Objects",
	"Functions",
	"System Variables",
	"Procedure keywords",
	"User Keywords 1",
	"User Keywords 2",
	"User Keywords 3",
	0
};

LexerModule lmMySQL(SCLEX_MYSQL, ColouriseMySQLDoc, "mysql", FoldMySQLDoc, mysqlWordListDesc);
<commit_msg>Updated to current scintilla-cocoa bzr release which does not try to use StyleContext within the folder.<commit_after>/**
 * Scintilla source code edit control
 * @file LexMySQL.cxx
 * Lexer for MySQL
 *
 * Improved by Mike Lischke <mike.lischke@sun.com>
 * Adopted from LexSQL.cxx by Anders Karlsson <anders@mysql.com>
 * Original work by Neil Hodgson <neilh@scintilla.org>
 * Copyright 1998-2005 by Neil Hodgson <neilh@scintilla.org>
 * The License.txt file describes the conditions under which this software may be distributed.
 */

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

#include "Platform.h"

#include "PropSet.h"
#include "Accessor.h"
#include "StyleContext.h"
#include "KeyWords.h"
#include "Scintilla.h"
#include "SciLexer.h"

#ifdef SCI_NAMESPACE
using namespace Scintilla;
#endif

static inline bool IsAWordChar(int ch) {
	return (ch < 0x80) && (isalnum(ch) || ch == '_');
}

static inline bool IsAWordStart(int ch) {
	return (ch < 0x80) && (isalpha(ch) || ch == '_');
}

static inline bool IsADoxygenChar(int ch) {
	return (islower(ch) || ch == '$' || ch == '@' ||
	        ch == '\\' || ch == '&' || ch == '<' ||
	        ch == '>' || ch == '#' || ch == '{' ||
	        ch == '}' || ch == '[' || ch == ']');
}

static inline bool IsANumberChar(int ch) {
	// Not exactly following number definition (several dots are seen as OK, etc.)
	// but probably enough in most cases.
	return (ch < 0x80) &&
	        (isdigit(ch) || toupper(ch) == 'E' ||
             ch == '.' || ch == '-' || ch == '+');
}

//--------------------------------------------------------------------------------------------------

/**
 * Check if the current content context represent a keyword and set the context state if so.
 */
static void CheckForKeyword(StyleContext& sc, WordList* keywordlists[])
{
  int length = sc.LengthCurrent() + 1; // +1 for the next char
  char* s = new char[length];
  sc.GetCurrentLowered(s, length);
  if (keywordlists[0]->InList(s))
    sc.ChangeState(SCE_MYSQL_MAJORKEYWORD);
  else
    if (keywordlists[1]->InList(s))
      sc.ChangeState(SCE_MYSQL_KEYWORD);
    else
      if (keywordlists[2]->InList(s))
        sc.ChangeState(SCE_MYSQL_DATABASEOBJECT);
      else
        if (keywordlists[3]->InList(s))
          sc.ChangeState(SCE_MYSQL_FUNCTION);
        else
          if (keywordlists[5]->InList(s))
            sc.ChangeState(SCE_MYSQL_PROCEDUREKEYWORD);
          else
            if (keywordlists[6]->InList(s))
              sc.ChangeState(SCE_MYSQL_USER1);
            else
              if (keywordlists[7]->InList(s))
                sc.ChangeState(SCE_MYSQL_USER2);
              else
                if (keywordlists[8]->InList(s))
                  sc.ChangeState(SCE_MYSQL_USER3);
  delete [] s;
}

//--------------------------------------------------------------------------------------------------

static void ColouriseMySQLDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[],
                            Accessor &styler)
{
	StyleContext sc(startPos, length, initStyle, styler);

	for (; sc.More(); sc.Forward())
  {
		// Determine if the current state should terminate.
		switch (sc.state)
    {
      case SCE_MYSQL_OPERATOR:
        sc.SetState(SCE_MYSQL_DEFAULT);
        break;
      case SCE_MYSQL_NUMBER:
        // We stop the number definition on non-numerical non-dot non-eE non-sign char.
        if (!IsANumberChar(sc.ch))
          sc.SetState(SCE_MYSQL_DEFAULT);
        break;
      case SCE_MYSQL_IDENTIFIER:
        // Switch from identifier to keyword state and open a new state for the new char.
        if (!IsAWordChar(sc.ch))
        {
          CheckForKeyword(sc, keywordlists);

          // Additional check for function keywords needed.
          // A function name must be followed by an opening parenthesis.
          if (sc.state == SCE_MYSQL_FUNCTION && sc.ch != '(')
            sc.ChangeState(SCE_MYSQL_DEFAULT);

          sc.SetState(SCE_MYSQL_DEFAULT);
        }
        break;
      case SCE_MYSQL_VARIABLE:
        if (!IsAWordChar(sc.ch))
          sc.SetState(SCE_MYSQL_DEFAULT);
        break;
      case SCE_MYSQL_SYSTEMVARIABLE:
        if (!IsAWordChar(sc.ch))
        {
          int length = sc.LengthCurrent() + 1;
          char* s = new char[length];
          sc.GetCurrentLowered(s, length);

          // Check for known system variables here.
          if (keywordlists[4]->InList(&s[2]))
            sc.ChangeState(SCE_MYSQL_KNOWNSYSTEMVARIABLE);
          delete [] s;

          sc.SetState(SCE_MYSQL_DEFAULT);
        }
        break;
      case SCE_MYSQL_QUOTEDIDENTIFIER:
        if (sc.ch == '`')
        {
          if (sc.chNext == '`')
            sc.Forward();	// Ignore it
          else
            sc.ForwardSetState(SCE_MYSQL_DEFAULT);
				}
  			break;
      case SCE_MYSQL_COMMENT:
      case SCE_MYSQL_HIDDENCOMMAND:
        if (sc.Match('*', '/'))
        {
          sc.Forward();
          sc.ForwardSetState(SCE_MYSQL_DEFAULT);
        }
        break;
      case SCE_MYSQL_COMMENTLINE:
        if (sc.atLineStart)
          sc.SetState(SCE_MYSQL_DEFAULT);
        break;
      case SCE_MYSQL_SQSTRING:
        if (sc.ch == '\\')
          sc.Forward(); // Escape sequence
        else
          if (sc.ch == '\'')
          {
            // End of single quoted string reached?
            if (sc.chNext == '\'')
              sc.Forward();
            else
              sc.ForwardSetState(SCE_MYSQL_DEFAULT);
          }
        break;
      case SCE_MYSQL_DQSTRING:
        if (sc.ch == '\\')
          sc.Forward(); // Escape sequence
        else
          if (sc.ch == '\"')
          {
            // End of single quoted string reached?
            if (sc.chNext == '\"')
              sc.Forward();
            else
              sc.ForwardSetState(SCE_MYSQL_DEFAULT);
          }
        break;
    }

    // Determine if a new state should be entered.
    if (sc.state == SCE_MYSQL_DEFAULT)
    {
      switch (sc.ch)
      {
        case '@':
          if (sc.chNext == '@')
          {
            sc.SetState(SCE_MYSQL_SYSTEMVARIABLE);
            sc.Forward(2); // Skip past @@.
          }
          else
            if (IsAWordStart(sc.ch))
            {
              sc.SetState(SCE_MYSQL_VARIABLE);
              sc.Forward(); // Skip past @.
            }
            else
              sc.SetState(SCE_MYSQL_OPERATOR);
          break;
        case '`':
          sc.SetState(SCE_MYSQL_QUOTEDIDENTIFIER);
          break;
        case '#':
          sc.SetState(SCE_MYSQL_COMMENTLINE);
          break;
        case '\'':
          sc.SetState(SCE_MYSQL_SQSTRING);
          break;
        case '\"':
          sc.SetState(SCE_MYSQL_DQSTRING);
          break;
        default:
          if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext)))
            sc.SetState(SCE_MYSQL_NUMBER);
          else
            if (IsAWordStart(sc.ch))
              sc.SetState(SCE_MYSQL_IDENTIFIER);
            else
              if (sc.Match('/', '*'))
              {
                sc.SetState(SCE_MYSQL_COMMENT);

                // Skip comment introducer and check for hidden command.
                sc.Forward(2);
                if (sc.ch == '!')
                {
                  sc.ChangeState(SCE_MYSQL_HIDDENCOMMAND);
                  sc.Forward();
                }
              }
              else
                if (sc.Match("--"))
                {
                  // Special MySQL single line comment.
                  sc.SetState(SCE_MYSQL_COMMENTLINE);
                  sc.Forward(2);

                  // Check the third character too. It must be a space or EOL.
                  if (sc.ch != ' ' && sc.ch != '\n' && sc.ch != '\r')
                    sc.ChangeState(SCE_MYSQL_OPERATOR);
                }
                else
                  if (isoperator(static_cast<char>(sc.ch)))
                    sc.SetState(SCE_MYSQL_OPERATOR);
      }
    }
  }

  // Do a final check for keywords if we currently have an identifier, to highlight them
  // also at the end of a line.
  if (sc.state == SCE_MYSQL_IDENTIFIER)
  {
    CheckForKeyword(sc, keywordlists);

    // Additional check for function keywords needed.
    // A function name must be followed by an opening parenthesis.
    if (sc.state == SCE_MYSQL_FUNCTION && sc.ch != '(')
      sc.ChangeState(SCE_MYSQL_DEFAULT);
  }

  sc.Complete();
}

//--------------------------------------------------------------------------------------------------

/**
 * Helper function to determine if we have a foldable comment currently.
 */
static bool IsStreamCommentStyle(int style)
{
	return style == SCE_MYSQL_COMMENT;
}

//--------------------------------------------------------------------------------------------------

/**
 * Code copied from StyleContext and modified to work here. Should go into Accessor as a
 * companion to Match()...
 */
bool MatchIgnoreCase(Accessor &styler, int currentPos, const char *s)
{
  for (int n = 0; *s; n++)
  {
    if (*s != tolower(styler.SafeGetCharAt(currentPos + n)))
      return false;
    s++;
  }
  return true;
}

//--------------------------------------------------------------------------------------------------

// Store both the current line's fold level and the next lines in the
// level store to make it easy to pick up with each increment.
static void FoldMySQLDoc(unsigned int startPos, int length, int initStyle, WordList *[], Accessor &styler)
{
	bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
	bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
	bool foldOnlyBegin = styler.GetPropertyInt("fold.sql.only.begin", 0) != 0;

	int visibleChars = 0;
	int lineCurrent = styler.GetLine(startPos);
	int levelCurrent = SC_FOLDLEVELBASE;
	if (lineCurrent > 0)
		levelCurrent = styler.LevelAt(lineCurrent - 1) >> 16;
	int levelNext = levelCurrent;

	int styleNext = styler.StyleAt(startPos);
	int style = initStyle;

  bool endFound = false;
	bool whenFound = false;
	bool elseFound = false;

  char nextChar = styler.SafeGetCharAt(startPos);
  for (unsigned int i = startPos; length > 0; i++, length--)
  {
		int stylePrev = style;
		style = styleNext;
		styleNext = styler.StyleAt(i + 1);

    char currentChar = nextChar;
    nextChar = styler.SafeGetCharAt(i + 1);
		bool atEOL = (currentChar == '\r' && nextChar != '\n') || (currentChar == '\n');

    switch (style)
    {
      case SCE_MYSQL_COMMENT:
        if (foldComment)
        {
          // Multiline comment style /* .. */.
          if (IsStreamCommentStyle(style))
          {
            // Increase level if we just start a foldable comment.
            if (!IsStreamCommentStyle(stylePrev))
              levelNext++;
            else
              // If we are in the middle of a foldable comment check if it ends now.
              // Don't end at the line end, though.
              if (!IsStreamCommentStyle(styleNext) && !atEOL)
                levelNext--;
          }
        }
        break;
      case SCE_MYSQL_COMMENTLINE:
        if (foldComment)
        {
          // Not really a standard, but we add support for single line comments
          // with special curly braces syntax as foldable comments too.
          // MySQL needs -- comments to be followed by space or control char
          if (styler.Match(startPos, "--"))
          {
            char chNext2 = styler.SafeGetCharAt(i + 2);
            char chNext3 = styler.SafeGetCharAt(i + 3);
            if (chNext2 == '{' || chNext3 == '{')
              levelNext++;
            else
              if (chNext2 == '}' || chNext3 == '}')
                levelNext--;
          }
        }
        break;
      case SCE_MYSQL_HIDDENCOMMAND:
        if (style != stylePrev)
          levelNext++;
        else
          if (style != styleNext)
            levelNext--;
        break;
      case SCE_MYSQL_OPERATOR:
        if (currentChar == '(')
          levelNext++;
        else
          if (currentChar == ')')
            levelNext--;
        break;
      case SCE_MYSQL_MAJORKEYWORD:
      case SCE_MYSQL_KEYWORD:
      case SCE_MYSQL_FUNCTION:
      case SCE_MYSQL_PROCEDUREKEYWORD:
        // Reserved and other keywords.
        if (style != stylePrev)
        {
          bool beginFound = MatchIgnoreCase(styler, startPos, "begin");
          bool ifFound = MatchIgnoreCase(styler, startPos, "if");
          bool thenFound = MatchIgnoreCase(styler, startPos, "then");
          bool whileFound = MatchIgnoreCase(styler, startPos, "while");
          bool loopFound = MatchIgnoreCase(styler, startPos, "loop");
          bool repeatFound = MatchIgnoreCase(styler, startPos, "repeat");

          if (!foldOnlyBegin && endFound && (ifFound || whileFound || loopFound))
          {
            endFound = false;
            levelNext--;
            if (levelNext < SC_FOLDLEVELBASE)
              levelNext = SC_FOLDLEVELBASE;

            // Note that "else" is special here. It may or may not be followed by an "if .. then",
            // but in any case the level stays the same. When followed by an "if .. then" the level
            // will be increased later, if not, then at eol.
          }
          else
            if (!foldOnlyBegin && MatchIgnoreCase(styler, startPos, "else"))
            {
              levelNext--;
              elseFound = true;
            }
            else
              if (!foldOnlyBegin && thenFound)
              {
                if (whenFound)
                  whenFound = false;
                else
                  levelNext++;
              }
              else
                if (ifFound)
                  elseFound = false;
                else
                  if (MatchIgnoreCase(styler, startPos, "when"))
                    whenFound = true;
                  else
                  {
                    if (beginFound)
                      levelNext++;
                    else
                      if (!foldOnlyBegin && (loopFound || repeatFound || whileFound))
                      {
                        if (endFound)
                          endFound = false;
                        else
                          levelNext++;
                      }
                      else
                        if (MatchIgnoreCase(styler, startPos, "end"))
                        {
                          // Multiple "end" in a row are counted multiple times!
                          if (endFound)
                          {
                            levelNext--;
                            if (levelNext < SC_FOLDLEVELBASE)
                              levelNext = SC_FOLDLEVELBASE;
                          }
                          endFound = true;
                          whenFound = false;
                        }
                  }
        }
        break;
    }

    // Handle the case of a trailing end without an if / while etc, as in the case of a begin.
		if (endFound)
    {
			endFound = false;
			levelNext--;
			if (levelNext < SC_FOLDLEVELBASE)
        levelNext = SC_FOLDLEVELBASE;
		}

		if (atEOL)
    {
			if (elseFound)
      {
				levelNext++;
        elseFound = false;
      }

			int levelUse = levelCurrent;
			int lev = levelUse | levelNext << 16;
			if (visibleChars == 0 && foldCompact)
				lev |= SC_FOLDLEVELWHITEFLAG;
			if (levelUse < levelNext)
				lev |= SC_FOLDLEVELHEADERFLAG;
			if (lev != styler.LevelAt(lineCurrent))
				styler.SetLevel(lineCurrent, lev);

			lineCurrent++;
			levelCurrent = levelNext;
			visibleChars = 0;
			endFound = false;
			whenFound = false;
		}

		if (!isspacechar(currentChar))
			visibleChars++;
	}
}

//--------------------------------------------------------------------------------------------------

static const char * const mysqlWordListDesc[] = {
	"Major Keywords",
	"Keywords",
	"Database Objects",
	"Functions",
	"System Variables",
	"Procedure keywords",
	"User Keywords 1",
	"User Keywords 2",
	"User Keywords 3",
	0
};

LexerModule lmMySQL(SCLEX_MYSQL, ColouriseMySQLDoc, "mysql", FoldMySQLDoc, mysqlWordListDesc);
<|endoftext|>


<commit_before><commit_msg>coverity#1266491 Untrusted loop bound<commit_after><|endoftext|>


<commit_before>#include "defines.h"

// Тестирование

// Функция, вызываемая при ошибке
void print_error(const char *error, const char *file, int line)
{
	printf("Error: %s\nFile: \"%s\"\nLine: %d\n\n", error, file, line);
	fflush(stdout);
#ifdef _WIN32
	printf("\nPress <Enter> to exit...\n");
	fflush(stdout);
	getchar();
#endif
	exit(1);
}

// Функция проверки на выход из допустимого диапазона значений
// во всех точках расчетной области процессора

void test_correct_P_S()
{
	for (int i = 0; i < (def.locNx); i++)
		for (int j = 0; j < (def.locNy); j++)
			for (int k = 0; k < (def.locNz); k++)
			{
				;// TODO: test values
			}
}

// Тест на NaN
// Синтаксис вызова test_nan(x, __FILE__, __LINE__);
void test_nan(double x, const char *file, int line)
{
#ifdef MY_TEST
	if (isnan(x))
	{
		printf("Error: NaN\nFile:\"%s\"\nLine:\"%d\"\n\n", file, line);
	}
	// Тестовое более жесткое ограничение именно для этой задачи
	/*if (x > 1e30 || x < -1e30)
	{
		printf("Error: NaN\nFile:\"%s\"\nLine:\"%d\"\n\n", file, line);
	}*/

#endif
}

// Тест на положительное и не NaN
// Синтаксис вызова test_positive(x, __FILE__, __LINE__);
void test_positive(double x, const char *file, int line)
{
#ifdef MY_TEST
	if (isnan(x))
	{
		printf("Error: NaN\nFile:\"%s\"\nLine:\"%d\"\n\n", file, line);
	}
	if (x < 0)
	{
		printf("Error: x<0\nFile:\"%s\"\nLine:\"%d\"\n\n", file, line);
	}
#endif
}

// Тест на вхождение насыщенностей в [0;1]
// Синтаксис вызова test_S(x, __FILE__, __LINE__);
void test_S(double S, const char *file, int line)
{
#ifdef MY_TEST
	if (isnan(S))
	{
		printf("Error: S=NaN\nFile:\"%s\"\nLine:\"%d\"\n\n", file, line);
	}
	if (S < 0)
	{
		printf("Error: S<0\nFile:\"%s\"\nLine:\"%d\"\n\n", file, line);
	}
	if (S > 1)
	{
		printf("Error: S>1\nFile:\"%s\"\nLine:\"%d\"\n\n", file, line);
	}
#endif
}

// Тест на вхождение скоростей в [-100;100]
// Синтаксис вызова test_u(x, __FILE__, __LINE__);
void test_u(double u, const char *file, int line)
{
#ifdef MY_TEST
	if (isnan(u))
	{
		printf("Error: u=NaN\nFile:\"%s\"\nLine:\"%d\"\n\n", file, line);
	}
	if (u < -1e8)
	{
		printf("Error: u<-100\nFile:\"%s\"\nLine:\"%d\"\n\n", file, line);
	}
	if (u > 1e8)
	{
		printf("Error: u>100\nFile:\"%s\"\nLine:\"%d\"\n\n", file, line);
	}
#endif
}

// Тест на вхождение плотностей в [-0;1500]
// Синтаксис вызова test_ro(x, __FILE__, __LINE__);
void test_ro(double ro, const char *file, int line)
{
#ifdef MY_TEST
	if (isnan(ro))
	{
		printf("Error: ro = NaN\nFile:\"%s\"\nLine:\"%d\"\n\n", file, line);
	}
	if (ro < 0)
	{
		printf("Error: ro < 0\nFile:\"%s\"\nLine:\"%d\"\n\n", file, line);
	}
	if (ro > 1e8)
	{
		printf("Error: ro > 1500\nFile:\"%s\"\nLine:\"%d\"\n\n", file, line);
	}
#endif
}

// Функция проверяет, что первый аргумент много больше (по модулю) второго
// Если это не так, печатается предупреждение
void test_arrowhead(double big, double small, const char *file, int line)
{
#ifdef MY_TEST_1
	if (fabs(big / 30) < fabs(small))
	{
		printf("Warning: See task parameters.\nFile:\"%s\"\nLine:\"%d\"\n\n", file, line);
	}
#endif
}

// Тест на корректность параметров задачи
void read_defines_test()
{
#ifdef MY_TEST
	test_positive(def.hx, __FILE__, __LINE__);
	test_positive(def.hy, __FILE__, __LINE__);
	test_positive(def.hz, __FILE__, __LINE__);
	test_positive(def.tau, __FILE__, __LINE__);
	test_positive(def.dt, __FILE__, __LINE__);
	test_positive(def.c_w, __FILE__, __LINE__);
	test_positive(def.c_n, __FILE__, __LINE__);
	test_positive(def.l, __FILE__, __LINE__);
	test_positive(def.beta_w, __FILE__, __LINE__);
	test_positive(def.beta_n, __FILE__, __LINE__);
	test_positive(def.ro0_w, __FILE__, __LINE__);
	test_positive(def.ro0_n, __FILE__, __LINE__);
	test_positive(def.mu_w, __FILE__, __LINE__);
	test_positive(def.mu_n, __FILE__, __LINE__);
	test_positive(def.g_const, __FILE__, __LINE__);
	test_positive(def.P_atm, __FILE__, __LINE__);

	test_positive(def.source, __FILE__, __LINE__);
	test_positive(def.newton_iterations, __FILE__, __LINE__);
	test_positive(def.timeX, __FILE__, __LINE__);
	test_positive(def.save_plots, __FILE__, __LINE__);
	test_positive(strlen(def.plots_dir), __FILE__, __LINE__);
	test_positive(def.print_screen, __FILE__, __LINE__);
	test_positive(def.Nx, __FILE__, __LINE__);
	test_positive(def.Ny, __FILE__, __LINE__);
	test_positive(def.Nz, __FILE__, __LINE__);

	test_positive(def.c_g, __FILE__, __LINE__);
	test_positive(def.beta_g, __FILE__, __LINE__);
	test_positive(def.ro0_g, __FILE__, __LINE__);
	test_positive(def.mu_g, __FILE__, __LINE__);
	test_S(def.S_w_gr, __FILE__, __LINE__);
	test_S(def.S_n_gr, __FILE__, __LINE__);

#ifdef ENERGY
	test_positive(def.T_0, __FILE__, __LINE__);
	test_positive(def.ro_r, __FILE__, __LINE__);
	test_positive(def.lambda0_w, __FILE__, __LINE__);
	test_positive(def.lambda0_n, __FILE__, __LINE__);
	test_positive(def.lambda0_g, __FILE__, __LINE__);
	test_positive(def.lambda0_r, __FILE__, __LINE__);
	test_positive(def.lambdaA_w, __FILE__, __LINE__);
	test_positive(def.lambdaA_n, __FILE__, __LINE__);
	test_positive(def.lambdaA_g, __FILE__, __LINE__);
	test_positive(def.c0_w, __FILE__, __LINE__);
	test_positive(def.c0_n, __FILE__, __LINE__);
	test_positive(def.c0_g, __FILE__, __LINE__);
	test_positive(def.c0_r, __FILE__, __LINE__);
	test_positive(def.C_w, __FILE__, __LINE__);
	test_positive(def.C_w2, __FILE__, __LINE__);
	test_positive(def.C_n, __FILE__, __LINE__);
	test_positive(def.C_g, __FILE__, __LINE__);
	test_positive(def.C_r, __FILE__, __LINE__);
	test_positive(def.alfa_w, __FILE__, __LINE__);
	test_positive(def.alfa_n, __FILE__, __LINE__);
#endif
#endif

}

<commit_msg>[IMPROVE] error printing for debugging<commit_after>#include "defines.h"

// Тестирование

// Функция, вызываемая при ошибке
void print_error(const char *error, const char *file, int line)
{
	printf("Error: %s\nFile: \"%s\"\nLine: %d\n\n", error, file, line);
	fflush(stdout);
#ifdef _WIN32
	printf("\nPress <Enter> to exit...\n");
	fflush(stdout);
	getchar();
#endif
	exit(1);
}

// Функция проверки на выход из допустимого диапазона значений
// во всех точках расчетной области процессора

void test_correct_P_S()
{
	for (int i = 0; i < (def.locNx); i++)
		for (int j = 0; j < (def.locNy); j++)
			for (int k = 0; k < (def.locNz); k++)
			{
				;// TODO: test values
			}
}

// Тест на NaN
// Синтаксис вызова test_nan(x, __FILE__, __LINE__);
void test_nan(double x, const char *file, int line)
{
#ifdef MY_TEST
	if (isnan(x))
	{
		print_error("NaN", file, line);
	}
	// Тестовое более жесткое ограничение именно для этой задачи
	/*if (x > 1e30 || x < -1e30)
	{
		printf("Error: NaN\nFile:\"%s\"\nLine:\"%d\"\n\n", file, line);
	}*/

#endif
}

// Тест на положительное и не NaN
// Синтаксис вызова test_positive(x, __FILE__, __LINE__);
void test_positive(double x, const char *file, int line)
{
#ifdef MY_TEST
	if (isnan(x))
	{
		print_error("NaN", file, line);
	}
	if (x < 0)
	{
		print_error("x<0", file, line);
	}
#endif
}

// Тест на вхождение насыщенностей в [0;1]
// Синтаксис вызова test_S(x, __FILE__, __LINE__);
void test_S(double S, const char *file, int line)
{
#ifdef MY_TEST
	if (isnan(S))
	{
		print_error("NaN", file, line);
	}
	if (S < 0)
	{
		print_error("S<0", file, line);
	}
	if (S > 1)
	{
		print_error("S>1", file, line);
	}
#endif
}

// Тест на вхождение скоростей в [-100;100]
// Синтаксис вызова test_u(x, __FILE__, __LINE__);
void test_u(double u, const char *file, int line)
{
#ifdef MY_TEST
	if (isnan(u))
	{
		print_error("NaN", file, line);
	}
	if (u < -1e8)
	{
		print_error("u < -1e8", file, line);
	}
	if (u > 1e8)
	{
		print_error("u > 1e8", file, line);
	}
#endif
}

// Тест на вхождение плотностей в [-0;1500]
// Синтаксис вызова test_ro(x, __FILE__, __LINE__);
void test_ro(double ro, const char *file, int line)
{
#ifdef MY_TEST
	if (isnan(ro))
	{
		print_error("NaN", file, line);
	}
	if (ro < 0)
	{
		print_error("ro < 0", file, line);
	}
	if (ro > 1e8)
	{
		print_error("ro > 1e8", file, line);
	}
#endif
}

// Функция проверяет, что первый аргумент много больше (по модулю) второго
// Если это не так, печатается предупреждение
void test_arrowhead(double big, double small, const char *file, int line)
{
#ifdef MY_TEST_1
	if (fabs(big / 30) < fabs(small))
	{
		printf("Warning: See task parameters.\nFile:\"%s\"\nLine:\"%d\"\n\n", file, line);
	}
#endif
}

// Тест на корректность параметров задачи
void read_defines_test()
{
#ifdef MY_TEST
	test_positive(def.hx, __FILE__, __LINE__);
	test_positive(def.hy, __FILE__, __LINE__);
	test_positive(def.hz, __FILE__, __LINE__);
	test_positive(def.tau, __FILE__, __LINE__);
	test_positive(def.dt, __FILE__, __LINE__);
	test_positive(def.c_w, __FILE__, __LINE__);
	test_positive(def.c_n, __FILE__, __LINE__);
	test_positive(def.l, __FILE__, __LINE__);
	test_positive(def.beta_w, __FILE__, __LINE__);
	test_positive(def.beta_n, __FILE__, __LINE__);
	test_positive(def.ro0_w, __FILE__, __LINE__);
	test_positive(def.ro0_n, __FILE__, __LINE__);
	test_positive(def.mu_w, __FILE__, __LINE__);
	test_positive(def.mu_n, __FILE__, __LINE__);
	test_positive(def.g_const, __FILE__, __LINE__);
	test_positive(def.P_atm, __FILE__, __LINE__);

	test_positive(def.source, __FILE__, __LINE__);
	test_positive(def.newton_iterations, __FILE__, __LINE__);
	test_positive(def.timeX, __FILE__, __LINE__);
	test_positive(def.save_plots, __FILE__, __LINE__);
	test_positive(strlen(def.plots_dir), __FILE__, __LINE__);
	test_positive(def.print_screen, __FILE__, __LINE__);
	test_positive(def.Nx, __FILE__, __LINE__);
	test_positive(def.Ny, __FILE__, __LINE__);
	test_positive(def.Nz, __FILE__, __LINE__);

	test_positive(def.c_g, __FILE__, __LINE__);
	test_positive(def.beta_g, __FILE__, __LINE__);
	test_positive(def.ro0_g, __FILE__, __LINE__);
	test_positive(def.mu_g, __FILE__, __LINE__);
	test_S(def.S_w_gr, __FILE__, __LINE__);
	test_S(def.S_n_gr, __FILE__, __LINE__);

#ifdef ENERGY
	test_positive(def.T_0, __FILE__, __LINE__);
	test_positive(def.ro_r, __FILE__, __LINE__);
	test_positive(def.lambda0_w, __FILE__, __LINE__);
	test_positive(def.lambda0_n, __FILE__, __LINE__);
	test_positive(def.lambda0_g, __FILE__, __LINE__);
	test_positive(def.lambda0_r, __FILE__, __LINE__);
	test_positive(def.lambdaA_w, __FILE__, __LINE__);
	test_positive(def.lambdaA_n, __FILE__, __LINE__);
	test_positive(def.lambdaA_g, __FILE__, __LINE__);
	test_positive(def.c0_w, __FILE__, __LINE__);
	test_positive(def.c0_n, __FILE__, __LINE__);
	test_positive(def.c0_g, __FILE__, __LINE__);
	test_positive(def.c0_r, __FILE__, __LINE__);
	test_positive(def.C_w, __FILE__, __LINE__);
	test_positive(def.C_w2, __FILE__, __LINE__);
	test_positive(def.C_n, __FILE__, __LINE__);
	test_positive(def.C_g, __FILE__, __LINE__);
	test_positive(def.C_r, __FILE__, __LINE__);
	test_positive(def.alfa_w, __FILE__, __LINE__);
	test_positive(def.alfa_n, __FILE__, __LINE__);
#endif
#endif

}

<|endoftext|>


<commit_before><commit_msg>Handle GetTextBreak returning -1<commit_after><|endoftext|>


<commit_before>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: gtksys.cxx,v $
 * $Revision: 1.7 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_vcl.hxx"

#include <svunx.h>
#include <vcl/svdata.hxx>
#include <vcl/window.hxx>
#include <plugins/gtk/gtkinst.hxx>
#include <cstdio>
#include <gdk/gdk.h>
#include <gtk/gtk.h>
#include <X11/Xlib.h>

SalSystem *GtkInstance::CreateSalSystem()
{
        return new GtkSalSystem();
}

GtkSalSystem::~GtkSalSystem()
{
}

int GtkSalSystem::ShowNativeDialog( const String& rTitle,
                                    const String& rMessage,
                                    const std::list< String >& rButtons,
                                    int nDefButton )
{

    ImplSVData* pSVData = ImplGetSVData();
    if( pSVData->mpIntroWindow )
            pSVData->mpIntroWindow->Hide();

#if OSL_DEBUG_LEVEL > 1
    fprintf( stderr, "GtkSalSystem::ShowNativeDialog\n");
#endif

    ByteString aTitle( rTitle, RTL_TEXTENCODING_UTF8 );
    ByteString aMessage( rMessage, RTL_TEXTENCODING_UTF8 );

    /* Create the dialogue */
    GtkWidget* mainwin = gtk_message_dialog_new
            ( NULL, (GtkDialogFlags)0, GTK_MESSAGE_WARNING,
              GTK_BUTTONS_NONE, aMessage.GetBuffer(), NULL );
    gtk_window_set_title( GTK_WINDOW( mainwin ), aTitle.GetBuffer() );

    gint nButtons = 0, nResponse;

    int nButton = 0;
    for( std::list< String >::const_iterator it = rButtons.begin(); it != rButtons.end(); ++it )
    {
        ByteString aLabel( *it, RTL_TEXTENCODING_UTF8 );

        if( nButton == nDefButton )
        {
            gtk_dialog_add_button( GTK_DIALOG( mainwin ), aLabel.GetBuffer(), nButtons );
            gtk_dialog_set_default_response( GTK_DIALOG( mainwin ), nButtons );
        }
        else
            gtk_dialog_add_button( GTK_DIALOG( mainwin ), aLabel.GetBuffer(), nButtons );
        nButtons++;
    }

    nResponse = gtk_dialog_run( GTK_DIALOG(mainwin) );
    if( nResponse == GTK_RESPONSE_NONE || nResponse == GTK_RESPONSE_DELETE_EVENT )
        nResponse = -1;

    gtk_widget_destroy( GTK_WIDGET(mainwin) );

    return nResponse;
}
<commit_msg>INTEGRATION: CWS hr51 (1.7.42); FILE MERGED 2008/06/06 14:56:11 hr 1.7.42.1: #i88947#: includes; std namespace; WaE<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: gtksys.cxx,v $
 * $Revision: 1.8 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_vcl.hxx"

#include <svunx.h>
#include <vcl/svdata.hxx>
#include <vcl/window.hxx>
#include <plugins/gtk/gtkinst.hxx>
#include <cstdio>
#include <gdk/gdk.h>
#include <gtk/gtk.h>
#include <X11/Xlib.h>

SalSystem *GtkInstance::CreateSalSystem()
{
        return new GtkSalSystem();
}

GtkSalSystem::~GtkSalSystem()
{
}

int GtkSalSystem::ShowNativeDialog( const String& rTitle,
                                    const String& rMessage,
                                    const std::list< String >& rButtons,
                                    int nDefButton )
{

    ImplSVData* pSVData = ImplGetSVData();
    if( pSVData->mpIntroWindow )
            pSVData->mpIntroWindow->Hide();

#if OSL_DEBUG_LEVEL > 1
    std::fprintf( stderr, "GtkSalSystem::ShowNativeDialog\n");
#endif

    ByteString aTitle( rTitle, RTL_TEXTENCODING_UTF8 );
    ByteString aMessage( rMessage, RTL_TEXTENCODING_UTF8 );

    /* Create the dialogue */
    GtkWidget* mainwin = gtk_message_dialog_new
            ( NULL, (GtkDialogFlags)0, GTK_MESSAGE_WARNING,
              GTK_BUTTONS_NONE, aMessage.GetBuffer(), NULL );
    gtk_window_set_title( GTK_WINDOW( mainwin ), aTitle.GetBuffer() );

    gint nButtons = 0, nResponse;

    int nButton = 0;
    for( std::list< String >::const_iterator it = rButtons.begin(); it != rButtons.end(); ++it )
    {
        ByteString aLabel( *it, RTL_TEXTENCODING_UTF8 );

        if( nButton == nDefButton )
        {
            gtk_dialog_add_button( GTK_DIALOG( mainwin ), aLabel.GetBuffer(), nButtons );
            gtk_dialog_set_default_response( GTK_DIALOG( mainwin ), nButtons );
        }
        else
            gtk_dialog_add_button( GTK_DIALOG( mainwin ), aLabel.GetBuffer(), nButtons );
        nButtons++;
    }

    nResponse = gtk_dialog_run( GTK_DIALOG(mainwin) );
    if( nResponse == GTK_RESPONSE_NONE || nResponse == GTK_RESPONSE_DELETE_EVENT )
        nResponse = -1;

    gtk_widget_destroy( GTK_WIDGET(mainwin) );

    return nResponse;
}
<|endoftext|>


<commit_before>/*
 * test_setupTunnel.cpp
 *
 *  Created on: 24 sep. 2015
 *      Author: Jesper
 */
#ifdef _MOCK_

#include "gtest/gtest.h"
#include "../src/setupTunnel.h"

class test_setupTunnel : public ::testing::Test {
protected:
	virtual void SetUp() {}
	virtual void TearDown() {}
};

#endif
<commit_msg>Test is running, but the test sucks<commit_after>/*
 * test_setupTunnel.cpp
 *
 *  Created on: 24 sep. 2015
 *      Author: Jesper
 */
#ifdef _MOCK_

#include "gtest/gtest.h"
#include "../src/setupTunnel.h"

class test_setupTunnel : public ::testing::Test {
protected:
	virtual void SetUp() {}
	virtual void TearDown() {}
};

TEST(test_setupTunnel, handleSetupTunnel) {
	setupTunnel st;
	StaticJsonBuffer<1000> buffer;
	JsonObject &reply = buffer.createObject();

	StaticJsonBuffer<200> jsonBuffer;
	char json[] = "{\"sensor\":\"gps\",\"msg_uuid\":1351824120,\"data\":[48.756080,2.302038]}";
	JsonObject &root = jsonBuffer.parseObject(json);

	EXPECT_EQ(1, st.handleSetupTunnel(root ,reply));

}
#endif
<|endoftext|>


<commit_before>#ifndef PROBLEM_HPP
#define PROBLEM_HPP

#include "node.hpp"

namespace AI
{

using std::shared_ptr;
using std::make_shared;

template <typename T>
struct Problem
{
	using state_type = T;
	using node_type = Node<state_type>;
	using node_ptr = typename node_type::node_ptr;
	using leafs_list = typename node_type::leafs_list;

	Problem(const Problem&) = delete;
	Problem(Problem&&) = default;

	Problem(T head)
	: mTree(make_shared<node_type>(head))
	{ }

	inline node_type & getRoot() const
	{ return *mTree; }

	inline node_ptr initial() const
	{ return mTree->shared_from_this(); }

	bool testGoal(const node_ptr &node) const
	{
		T && val = node->getState();
		this->watch(val);
		return this->isGoal(val);
	}

	virtual bool isGoal(const T &value) const = 0;

	virtual leafs_list successors( const node_ptr &state) const
	{ return state->expand(); }

	virtual void pathCost(const node_ptr &state1) const {}

	virtual void watch(const T & n) const {
		std::cout << n << std::endl;
	}

protected:
	using daddy_type = Problem<T>;

private:
	const node_ptr mTree;
};

namespace Private
{

template<typename T, typename G >
struct ProblemMaker : public Problem<T>
{

	ProblemMaker(T root, T goal, const G &gen )
	: Problem<T>(forward<T>(root)), mGoal(forward<T>(goal)), mGenerator(gen)
	{ }

  	bool isGoal (const T & value) const override {
		if ( value == mGoal )
			return true;
		return false;
	}

	virtual typename Problem<T>::leafs_list
	successors(const typename Problem<T>::node_ptr &state) const override
	{
		return mGenerator(state);
	}

private:
	const T mGoal;
	const G &mGenerator;
};

}

using namespace Private;

template <typename T, typename G>
ProblemMaker<T,G> makeProblem(T root, T goal, G gen)
{
	return ProblemMaker<T,G>(root, goal, gen);
}

#define MAKE_PROBLEM(ROOT, GOAL, STATE, GEN) makeProblem(ROOT, GOAL, [&]( \
			const Node<decltype(ROOT)>::node_ptr & STATE) { \
				typename Problem<decltype(ROOT)>::leafs_list GEN;

#define END_PROBLEM })

}

#endif
<commit_msg>passing graph/tree directly to makeProblem<commit_after>#ifndef PROBLEM_HPP
#define PROBLEM_HPP

#include "node.hpp"

namespace AI
{

using std::shared_ptr;
using std::make_shared;

template <typename T>
struct Problem
{
	using state_type = T;
	using node_type = Node<state_type>;
	using node_ptr = typename node_type::node_ptr;
	using leafs_list = typename node_type::leafs_list;

	Problem(const Problem&) = delete;
	Problem(Problem&&) = default;

	Problem(node_ptr && head)
		: mTree(move(head))
	{ }

	Problem(T head)
	: mTree(make_shared<node_type>(head))
	{ }

	inline node_type & getRoot() const
	{ return *mTree; }

	inline node_ptr initial() const
	{ return mTree->shared_from_this(); }

	bool testGoal(const node_ptr &node) const
	{
		T && val = node->getState();
		this->watch(val);
		return this->isGoal(val);
	}

	virtual bool isGoal(const T &value) const = 0;

	virtual leafs_list successors( const node_ptr &state) const
	{ return state->expand(); }

	virtual void watch(const T & n) const {
		std::cout << n << std::endl;
	}

protected:
	using daddy_type = Problem<T>;

private:
	const node_ptr mTree;
};

namespace Private
{

template<typename T, typename G >
struct ProblemMaker : public Problem<T>
{

	ProblemMaker(T root, T goal, const G &gen )
	: Problem<T>(forward<T>(root)), mGoal(forward<T>(goal)), mGenerator(gen)
	{ }

	ProblemMaker(typename Problem<T>::node_ptr node, T goal, const G &gen )
	: Problem<T>(move(node)), mGoal(forward<T>(goal)), mGenerator(gen)
	{ }

  	bool isGoal (const T & value) const override {
		if ( value == mGoal )
			return true;
		return false;
	}

	virtual typename Problem<T>::leafs_list
	successors(const typename Problem<T>::node_ptr &state) const override
	{
		return mGenerator(state);
	}

private:
	const T mGoal;
	const G &mGenerator;
};

template<typename T>
struct DefaultExpander
{
	typename Problem<T>::leafs_list
	operator()(const typename Problem<T>::node_ptr &state) const
	{ return state->expand(); }
};

}

using namespace Private;

template <typename T, typename G>
ProblemMaker<T,G> makeProblem(T root, T goal, G gen )
{
	return ProblemMaker<T,G>(forward<T>(root), forward<T>(goal), gen);
}

template <typename T, typename G = DefaultExpander<T>>
ProblemMaker<T,G> makeProblem(const typename Problem<T>::node_ptr &graph, T goal)
{
	G gen;
	return ProblemMaker<T,G>(graph, forward<T>(goal), gen);
}

#define MAKE_PROBLEM(ROOT, GOAL, NODE, STATE, GEN) makeProblem(ROOT, GOAL, [&]( \
			const Node<decltype(ROOT)>::node_ptr & NODE) { \
		typename Problem<decltype(ROOT)>::leafs_list GEN; \
		auto STATE = NODE ->getState();

#define END_PROBLEM })

}

#endif
<|endoftext|>


<commit_before>#ifndef __ENVIRE_MAPS_LOCAL_MAP_HPP__
#define __ENVIRE_MAPS_LOCAL_MAP_HPP__

#include <base/Eigen.hpp>

#include <boost/shared_ptr.hpp>

#include <string>

namespace envire { namespace maps
{
    /**@brief LocalMapType
     * The type of the LocalMap
     */

    // TODO: do we need unknown type?
    enum LocalMapType
    {
        GRID_MAP = 0,
        GEOMETRIC_MAP = 1,
        MLS_MAP = 2,
        TOPOLOGICAL_MAP = 3
    };

    struct LocalMapData
    {
        LocalMapData()
            : offset(base::Transform3d::Identity()) {};

        /**  string id of this local map **/
        std::string id;

        /** Offset within the grid. The description of the local map frame.
         * It will be the offset with respect
         * to the bottom left corner (origin) of the map.
         * For the time being we use 3D transformation.
         *
         *
         **/
        base::Transform3d offset;

        /** map_type of this local map **/
        LocalMapType map_type;

        /** EPSG_code that provides the geo-localized coordinate system **/
        std::string EPSG_code;

        /** The EPSG code depends in the coordinate system used for the
         * local map "NONE" in case of not geo-referenced map.
         * Example: "EPSG::4978" for the World Geodetic System 1984 (WGS-84)
         * Example: "EPSG::3199" Spain - Canary Islands onshore and offshore.
         * with bounds are [-21.93W, -11.75E] and [24.6S, 11.75N] using the
         * World Geodetic System 1984 (WGS-84) coordinate reference system
         * (CRS).
         * Example: "EPSG::5243" ETRS89 / LCC Germany (E-N) Bremen area with
         * WGS084 CRS
         * Reference: https://www.epsg-registry.org **/
    };

    /**@brief LocalMap
     * Local map with respect to a given reference frame
     * A local map is the basic element to form a global
     * map (set of local maps structured in a tree).
     */
    class LocalMap
    {
        public:
            typedef boost::shared_ptr<LocalMap> Ptr;

            LocalMap()
                : data_ptr(new LocalMapData())
            {
            }

            // TODO: which map_type should be set by default
            LocalMap(const boost::shared_ptr<LocalMapData> &data)
                : data_ptr(data)
            {
            }

            LocalMap(const LocalMap& other)
                : data_ptr(new LocalMapData(*(other.data_ptr.get())))
            {
            }

            virtual ~LocalMap() {};

            const std::string& getId() const
            {
                return data_ptr->id;
            }

            std::string& getId()
            {
                return data_ptr->id;
            }

            const base::Transform3d& getOffset() const
            {
                return data_ptr->offset;
            }

            base::Transform3d& getOffset()
            {
                return data_ptr->offset;
            }

        protected:
            boost::shared_ptr<LocalMapData> data_ptr;
    };
}}
#endif // __ENVIRE_MAPS_LOCAL_MAP_HPP__
<commit_msg>add documentation to LocalMap<commit_after>#ifndef __ENVIRE_MAPS_LOCAL_MAP_HPP__
#define __ENVIRE_MAPS_LOCAL_MAP_HPP__

#include <base/Eigen.hpp>

#include <boost/shared_ptr.hpp>

#include <string>

namespace envire { namespace maps
{
    /**@brief LocalMapType
     * The type of the LocalMap
     */

    // TODO: do we need unknown type?
    enum LocalMapType
    {
        GRID_MAP = 0,
        GEOMETRIC_MAP = 1,
        MLS_MAP = 2,
        TOPOLOGICAL_MAP = 3
    };

    struct LocalMapData
    {
        // TODO: which map_type should be set by default
        LocalMapData()
            : offset(base::Transform3d::Identity()) {};

        /**  string id of this local map **/
        std::string id;

        /** Offset within the grid. The description of the local map frame.
         * It will be the offset with respect
         * to the bottom left corner (origin) of the map.
         * For the time being we use 3D transformation.
         *
         *
         **/
        base::Transform3d offset;

        /** map_type of this local map **/
        LocalMapType map_type;

        /** EPSG_code that provides the geo-localized coordinate system **/
        std::string EPSG_code;

        /** The EPSG code depends in the coordinate system used for the
         * local map "NONE" in case of not geo-referenced map.
         * Example: "EPSG::4978" for the World Geodetic System 1984 (WGS-84)
         * Example: "EPSG::3199" Spain - Canary Islands onshore and offshore.
         * with bounds are [-21.93W, -11.75E] and [24.6S, 11.75N] using the
         * World Geodetic System 1984 (WGS-84) coordinate reference system
         * (CRS).
         * Example: "EPSG::5243" ETRS89 / LCC Germany (E-N) Bremen area with
         * WGS084 CRS
         * Reference: https://www.epsg-registry.org **/
    };

    /**@brief LocalMap
     * Local map with respect to a given reference frame
     * A local map is the basic element to form a global
     * map (set of local maps structured in a tree).
     */
    class LocalMap
    {
        public:
            typedef boost::shared_ptr<LocalMap> Ptr;

            LocalMap()
                : data_ptr(new LocalMapData())
            {
            }

            /**
             * @brief [brief description]
             * @details to share same content (LocalMapData) between various instance of LocalMap
             *
             * @param data [description]
             */
            LocalMap(const boost::shared_ptr<LocalMapData> &data)
                : data_ptr(data)
            {
            }

            /**
             * @brief make copy without sharing the content
             * @details the copy instance owns a new content (LocalMapData)
             *
             * @param other [description]
             */
            LocalMap(const LocalMap& other)
                : data_ptr(new LocalMapData(*(other.data_ptr.get())))
            {
            }

            virtual ~LocalMap() {};

            const std::string& getId() const
            {
                return data_ptr->id;
            }

            std::string& getId()
            {
                return data_ptr->id;
            }

            const base::Transform3d& getOffset() const
            {
                return data_ptr->offset;
            }

            base::Transform3d& getOffset()
            {
                return data_ptr->offset;
            }

        protected:
            boost::shared_ptr<LocalMapData> data_ptr;
    };
}}
#endif // __ENVIRE_MAPS_LOCAL_MAP_HPP__
<|endoftext|>


<commit_before>#include "process.h"
#include "native.h"
#include <stdexcept>
#include <set>
#include <vector>
#include <fstream>
#include <sstream>
#include <cstring>
#include <iostream>

#include "stb/stb_image.h"
#include "stb/stb_image_write.h"
#include "stb/stb_image_resize.h"

namespace scpak
{
    const char *PakInfoFileName = "scpak.info";

    void unpack(const PakFile &pak, const std::string &dirPath, bool unpackText, bool unpackTexture, bool unpackFont)
    {
        std::string dirPathSafe = dirPath;
        if (*dirPathSafe.rbegin() != pathsep)
            dirPathSafe += pathsep;
        // find all the directories we possibly need to create
        std::set<std::string> directoriesToCreate;
        directoriesToCreate.insert(dirPath);
        for (const PakItem &item : pak.contents())
        {
            std::string filePath = item.name;
            std::size_t pend = filePath.rfind('/');
            if (pend == std::string::npos)
                continue;
            std::size_t p = 0;
            while (p != pend)
            {
                p = filePath.find('/', p+1);
                directoriesToCreate.insert(dirPathSafe + filePath.substr(0, p));
            }
        }
        // create directories if necessary
        for (const std::string &dir : directoriesToCreate)
            if (!pathExists(dir.c_str()))
                createDirectory(dir.c_str());
        // unpack contents
        std::vector<std::string> infoLines;
        for (const PakItem &item : pak.contents())
        {
            std::stringstream lineBuffer;
            lineBuffer << item.name << ':' << item.type;
            std::string itemType = item.type;
            if (unpackText && itemType == "System.String")
            {
                unpack_string(dirPathSafe, item);
            }
            else if (unpackText && itemType == "System.Xml.Linq.XElement")
            {
                unpack_string(dirPathSafe, item);
            }
            else if (unpackTexture && itemType == "Engine.Graphics.Texture2D")
            {
                std::string fileName = dirPathSafe + item.name + ".tga";
                const byte *data = item.data.data();
                const int &width = *reinterpret_cast<const int*>(data);
                const int &height = *(reinterpret_cast<const int*>(data) + 1);
                const int &mipmapLevel = *(reinterpret_cast<const int*>(data) + 2);
                const void *imageData = reinterpret_cast<const void*>(data + sizeof(int) * 3);
                stbi_write_tga(fileName.c_str(), width, height, 4, imageData);

                lineBuffer << ':' << mipmapLevel;
            }
            else if (unpackFont && itemType == "Engine.Media.BitmapFont")
            {
                unpack_bitmapFont(dirPathSafe, item);
            }
            else
            {
            unpack_raw:
                // just write out raw data
                std::ofstream fout(dirPathSafe + item.name, std::ios::binary);
                fout.write(reinterpret_cast<const char*>(item.data.data()), item.length);
                fout.close();
            }
            infoLines.push_back(lineBuffer.str());
        }
        // write info file - we need to repack it later
        std::ofstream fout(dirPathSafe + PakInfoFileName);
        for (const std::string &line : infoLines)
            fout << line << std::endl;
        fout.close();
    }

    PakFile pack(const std::string &dirPath, bool packText, bool packTexture, bool packFont)
    {
        PakFile pak;
        std::vector<PakItem> contents = pak.contents();
        std::string dirPathSafe = dirPath;
        if (*dirPathSafe.rbegin() != pathsep)
            dirPathSafe += pathsep;
        std::ifstream fPakInfo(dirPathSafe + PakInfoFileName);
        if (!fPakInfo)
            throw std::runtime_error("cannot open " + dirPathSafe + PakInfoFileName);
        std::string line;
        int lineNumber = 1;
        while(std::getline(fPakInfo, line))
        {
            std::size_t split1 = line.find(':');
            if (split1 == std::string::npos)
            {
                std::stringstream ss;
                ss << "cannot parse " << PakInfoFileName << ", line " << lineNumber;
                throw std::runtime_error(ss.str());
            }
            std::string name = line.substr(0, split1);
            std::size_t split2 = line.find(':', split1+1);
            std::string type = line.substr(split1+1, split2-split1-1);
            std::string extraInfo;
            if (split2 != std::string::npos)
                extraInfo = line.substr(split2+1, std::string::npos);
            PakItem item;
            item.name = name;
            item.type = type;

            if (packText && type == "System.String")
            {
                pack_string(dirPathSafe, item);
            }
            else if (packText && type == "System.Xml.Linq.XElement")
            {
                pack_string(dirPathSafe, item);
            }
            else if (packTexture && type == "Engine.Graphics.Texture2D")
            {
                // not ready yet
                std::string filePathRaw = dirPathSafe + name;
                std::string fileName = filePathRaw;
                if (pathExists((filePathRaw + ".tga").c_str()))
                    fileName += ".tga";
                else if (pathExists((filePathRaw + ".png").c_str()))
                    fileName += ".png";
                else if (pathExists((filePathRaw + ".bmp").c_str()))
                    fileName += ".bmp";
                else if (pathExists(filePathRaw.c_str()))
                    goto pack_raw; // -_-
                else
                    throw std::runtime_error("cannot find image file: " + name);
                int width, height, comp;
                unsigned char *data = stbi_load(fileName.c_str(), &width, &height, &comp, 0);
                if (data == nullptr)
                    throw std::runtime_error("cannot load image file: " + name);
                if (comp != 4)
                    throw std::runtime_error("image must have 4 components in every pixel: " + name);
                int mipmapLevel = 0;
                if (!extraInfo.empty())
                    std::stringstream(extraInfo) >> mipmapLevel;
                item.length = sizeof(int) * 3 + calcMipmapSize(width, height, mipmapLevel) * comp;
                item.data.resize(item.length);
                *reinterpret_cast<int*>(item.data.data()) = width;
                *(reinterpret_cast<int*>(item.data.data()) + 1) = height;
                *(reinterpret_cast<int*>(item.data.data()) + 2) = mipmapLevel;
                std::memcpy(item.data.data() + sizeof(int) * 3, data, width*height*comp);
                stbi_image_free(data);
                int offset = generateMipmap(width, height, mipmapLevel, item.data.data() + sizeof(int) * 3);
            }
            else if (packFont && type == "Engine.Media.BitmapFont")
            {
                pack_bitmapFont(dirPathSafe, item);
            }
            else
            {
            pack_raw:
                std::string filePath = dirPathSafe + name;
                int fileSize = getFileSize(filePath.c_str());
                std::ifstream file(filePath, std::ios::binary);
                item.data.resize(fileSize);
                item.length = fileSize;
                file.read(reinterpret_cast<char*>(item.data.data()), fileSize);
                file.close();
            }
            pak.addItem(std::move(item));
            ++lineNumber;
        }
        fPakInfo.close();
        return pak;
    }

    int calcMipmapSize(int width, int height, int level)
    {
        if (level == 1)
            return width * height;
        if (!isPowerOfTwo(width) || !isPowerOfTwo(height))
            throw std::runtime_error("generating mipmaps for non-power of 2 images not supported");

        int size = width * height;
        while (width != 1 && height != 1 && level > 1)
        {
            width /= 2;
            height /= 2;
            --level;
            size += width * height;
        }
        if (width == 1 && height != 1)
            while (height != 1 && level > 1)
            {
                height /= 2;
                --level;
                size += width * height;
            }
        else if (height == 1 && width != 1)
            while (width != 1 && level > 1)
            {
                width /= 2;
                --level;
                size += width*height;
            }
        return size;
    }

    int generateMipmap(int width, int height, int level, unsigned char *image)
    {
        const int comp = 4;

        if (level == 1)
            return width * height * comp;
        if (!isPowerOfTwo(width) || !isPowerOfTwo(height))
            throw std::runtime_error("generating mipmaps for non-power of 2 images not supported");

        int offset = width * height * comp;
        int w=width, h=height;
        while (w != 1 && h%2 != 1 && level > 1)
        {
            w /= 2;
            h /= 2;
            --level;
            stbir_resize_uint8(image, width, height, 0,
                               image+offset, w, h, 0,
                               comp);
            offset += w * h * comp;
        }
        if (w == 1 && h != 1)
            while (h != 1 && level > 1)
            {
                h /= 2;
                --level;
                stbir_resize_uint8(image, width, height, 0,
                                   image + offset, w, h, 0,
                                   comp);
                offset += w * h * comp;
            }
        else if (h == 1 && w != 1)
            while (w != 1 && level > 1)
            {
                w /= 2;
                --level;
                stbir_resize_uint8(image, width, height, 0,
                                   image + offset, w, h, 0,
                                   comp);
                offset += w * h * comp;
            }
        return offset;
    }

    void unpack_string(const std::string &outputPath, const PakItem &item)
    {
        std::string fileName = outputPath + item.name;
        if (item.type == "System.String")
            fileName += ".txt";
        else if (item.type == "System.Xml.Linq.XElement")
            fileName += ".xml";
        else
            throw std::runtime_error("wrong item type");

        std::ofstream fout;
        fout.open(fileName, std::ios::binary);
        MemoryBinaryReader reader(item.data.data());
        std::string value = reader.readString();
        fout.write(value.data(), value.length());
        fout.close();
    }

    void pack_string(const std::string &inputPath, PakItem &item)
    {
        std::string fileName = inputPath + item.name;
        if (item.type == "System.String")
            fileName += ".txt";
        else if (item.type == "System.Xml.Linq.XElement")
            fileName += ".xml";
        else
            throw std::runtime_error("wrong item type");

        std::ifstream fin;
        fin.open(fileName, std::ios::binary);
        fin.seekg(0, std::ios::beg);
        int offsetBeg = fin.tellg();
        fin.seekg(0, std::ios::end);
        int offsetEnd = fin.tellg();
        int fileSize = offsetEnd - offsetBeg;
        fin.seekg(0, std::ios::beg);

        item.data.resize(fileSize+5);
        MemoryBinaryWriter writer(item.data.data());
        writer.write7BitEncodedInt(fileSize);
        item.length = fileSize + writer.position;
        fin.read(reinterpret_cast<char*>(item.data.data()+writer.position), fileSize);
        fin.close();
    }

    void unpack_bitmapFont(const std::string &outputDir, const PakItem &item)
    {
        std::string listFileName = outputDir + item.name + ".lst";
        std::string textureFileName = outputDir + item.name + ".tga";

        MemoryBinaryReader reader(item.data.data());
        int glyphCount = reader.readInt();
        std::vector<GlyphInfo> glyphList;
        glyphList.resize(glyphCount);
        for (int i = 0; i < glyphCount; ++i)
        {
            GlyphInfo &glyph = glyphList[i];
            glyph.unicode = reader.readUtf8Char();
            glyph.texCoord1.x = reader.readFloat();
            glyph.texCoord1.y = reader.readFloat();
            glyph.texCoord2.x = reader.readFloat();
            glyph.texCoord2.y = reader.readFloat();
            glyph.offset.x = reader.readFloat();
            glyph.offset.y = reader.readFloat();
            glyph.width = reader.readFloat();
        }
        float glyphHeight = reader.readFloat();
        Vector2f spacing;
        spacing.x = reader.readFloat();
        spacing.y = reader.readFloat();
        float scale = reader.readFloat();
        int fallbackCode = reader.readUtf8Char();

        int width = reader.readInt();
        int height = reader.readInt();
        int mipmapLevel = reader.readInt();

        stbi_write_tga(textureFileName.c_str(), width, height, 4, item.data.data() + reader.position);

        std::ofstream fList;
        fList.open(listFileName);
        fList << glyphCount << std::endl;
        for (int i = 0; i < glyphCount; ++i)
        {
            GlyphInfo &glyph = glyphList[i];
            fList << glyph.unicode << '\t'
                << glyph.texCoord1.x << '\t' << glyph.texCoord1.y << '\t'
                << glyph.texCoord2.x << '\t' << glyph.texCoord2.y << '\t'
                << glyph.offset.x << '\t' << glyph.offset.y << '\t'
                << glyph.width << std::endl;
        }
        fList << glyphHeight << std::endl;
        fList << spacing.x << '\t' << spacing.y << std::endl;
        fList << scale << std::endl;
        fList << fallbackCode << std::endl;
        fList.close();
    }

    void pack_bitmapFont(const std::string &inputDir, PakItem &item)
    {
        std::string listFileName = inputDir + item.name + ".lst";
        std::string textureFileName = inputDir + item.name + ".tga";

        std::ifstream fList;
        fList.open(listFileName);
        int glyphCount;
        fList >> glyphCount;

        int width, height, comp;
        unsigned char *data = stbi_load(textureFileName.c_str(), &width, &height, &comp, 4);
        item.data.resize(sizeof(GlyphInfo) * glyphCount + 50 + width*height * 4);

        MemoryBinaryWriter writer(item.data.data());
        writer.writeInt(glyphCount);
        for (int i = 0; i < glyphCount; ++i)
        {
            GlyphInfo glyph;
            fList >> glyph.unicode
                >> glyph.texCoord1.x >> glyph.texCoord1.y
                >> glyph.texCoord2.x >> glyph.texCoord2.y
                >> glyph.offset.x >> glyph.offset.y
                >> glyph.width;
            writer.writeUtf8Char(glyph.unicode);
            writer.writeFloat(glyph.texCoord1.x);
            writer.writeFloat(glyph.texCoord1.y);
            writer.writeFloat(glyph.texCoord2.x);
            writer.writeFloat(glyph.texCoord2.y);
            writer.writeFloat(glyph.offset.x);
            writer.writeFloat(glyph.offset.y);
            writer.writeFloat(glyph.width);
        }
        float glyphHeight; fList >> glyphHeight;
        Vector2f spacing; fList >> spacing.x >> spacing.y;
        float scale; fList >> scale;
        int fallbackCode; fList >> fallbackCode;
        writer.writeFloat(glyphHeight);
        writer.writeFloat(spacing.x);
        writer.writeFloat(spacing.y);
        writer.writeFloat(scale);
        writer.writeUtf8Char(fallbackCode);
        fList.close();

        writer.writeInt(width);
        writer.writeInt(height);
        writer.writeInt(1);
        std::memcpy(item.data.data() + writer.position, data, width*height * 4);
        item.length = writer.position + width*height * 4;

        stbi_image_free(data);
    }

    bool isPowerOfTwo(int n)
    {
        return (n & (n - 1)) == 0;
    }
}

<commit_msg>change mete information file name<commit_after>#include "process.h"
#include "native.h"
#include <stdexcept>
#include <set>
#include <vector>
#include <fstream>
#include <sstream>
#include <cstring>
#include <iostream>

#include "stb/stb_image.h"
#include "stb/stb_image_write.h"
#include "stb/stb_image_resize.h"

namespace scpak
{
    const char *PakInfoFileName = "scpak.meta";

    void unpack(const PakFile &pak, const std::string &dirPath, bool unpackText, bool unpackTexture, bool unpackFont)
    {
        std::string dirPathSafe = dirPath;
        if (*dirPathSafe.rbegin() != pathsep)
            dirPathSafe += pathsep;
        // find all the directories we possibly need to create
        std::set<std::string> directoriesToCreate;
        directoriesToCreate.insert(dirPath);
        for (const PakItem &item : pak.contents())
        {
            std::string filePath = item.name;
            std::size_t pend = filePath.rfind('/');
            if (pend == std::string::npos)
                continue;
            std::size_t p = 0;
            while (p != pend)
            {
                p = filePath.find('/', p+1);
                directoriesToCreate.insert(dirPathSafe + filePath.substr(0, p));
            }
        }
        // create directories if necessary
        for (const std::string &dir : directoriesToCreate)
            if (!pathExists(dir.c_str()))
                createDirectory(dir.c_str());
        // unpack contents
        std::vector<std::string> infoLines;
        for (const PakItem &item : pak.contents())
        {
            std::stringstream lineBuffer;
            lineBuffer << item.name << ':' << item.type;
            std::string itemType = item.type;
            if (unpackText && itemType == "System.String")
            {
                unpack_string(dirPathSafe, item);
            }
            else if (unpackText && itemType == "System.Xml.Linq.XElement")
            {
                unpack_string(dirPathSafe, item);
            }
            else if (unpackTexture && itemType == "Engine.Graphics.Texture2D")
            {
                std::string fileName = dirPathSafe + item.name + ".tga";
                const byte *data = item.data.data();
                const int &width = *reinterpret_cast<const int*>(data);
                const int &height = *(reinterpret_cast<const int*>(data) + 1);
                const int &mipmapLevel = *(reinterpret_cast<const int*>(data) + 2);
                const void *imageData = reinterpret_cast<const void*>(data + sizeof(int) * 3);
                stbi_write_tga(fileName.c_str(), width, height, 4, imageData);

                lineBuffer << ':' << mipmapLevel;
            }
            else if (unpackFont && itemType == "Engine.Media.BitmapFont")
            {
                unpack_bitmapFont(dirPathSafe, item);
            }
            else
            {
            unpack_raw:
                // just write out raw data
                std::ofstream fout(dirPathSafe + item.name, std::ios::binary);
                fout.write(reinterpret_cast<const char*>(item.data.data()), item.length);
                fout.close();
            }
            infoLines.push_back(lineBuffer.str());
        }
        // write info file - we need to repack it later
        std::ofstream fout(dirPathSafe + PakInfoFileName);
        for (const std::string &line : infoLines)
            fout << line << std::endl;
        fout.close();
    }

    PakFile pack(const std::string &dirPath, bool packText, bool packTexture, bool packFont)
    {
        PakFile pak;
        std::vector<PakItem> contents = pak.contents();
        std::string dirPathSafe = dirPath;
        if (*dirPathSafe.rbegin() != pathsep)
            dirPathSafe += pathsep;
        std::ifstream fPakInfo(dirPathSafe + PakInfoFileName);
        if (!fPakInfo)
            throw std::runtime_error("cannot open " + dirPathSafe + PakInfoFileName);
        std::string line;
        int lineNumber = 1;
        while(std::getline(fPakInfo, line))
        {
            std::size_t split1 = line.find(':');
            if (split1 == std::string::npos)
            {
                std::stringstream ss;
                ss << "cannot parse " << PakInfoFileName << ", line " << lineNumber;
                throw std::runtime_error(ss.str());
            }
            std::string name = line.substr(0, split1);
            std::size_t split2 = line.find(':', split1+1);
            std::string type = line.substr(split1+1, split2-split1-1);
            std::string extraInfo;
            if (split2 != std::string::npos)
                extraInfo = line.substr(split2+1, std::string::npos);
            PakItem item;
            item.name = name;
            item.type = type;

            if (packText && type == "System.String")
            {
                pack_string(dirPathSafe, item);
            }
            else if (packText && type == "System.Xml.Linq.XElement")
            {
                pack_string(dirPathSafe, item);
            }
            else if (packTexture && type == "Engine.Graphics.Texture2D")
            {
                // not ready yet
                std::string filePathRaw = dirPathSafe + name;
                std::string fileName = filePathRaw;
                if (pathExists((filePathRaw + ".tga").c_str()))
                    fileName += ".tga";
                else if (pathExists((filePathRaw + ".png").c_str()))
                    fileName += ".png";
                else if (pathExists((filePathRaw + ".bmp").c_str()))
                    fileName += ".bmp";
                else if (pathExists(filePathRaw.c_str()))
                    goto pack_raw; // -_-
                else
                    throw std::runtime_error("cannot find image file: " + name);
                int width, height, comp;
                unsigned char *data = stbi_load(fileName.c_str(), &width, &height, &comp, 0);
                if (data == nullptr)
                    throw std::runtime_error("cannot load image file: " + name);
                if (comp != 4)
                    throw std::runtime_error("image must have 4 components in every pixel: " + name);
                int mipmapLevel = 0;
                if (!extraInfo.empty())
                    std::stringstream(extraInfo) >> mipmapLevel;
                item.length = sizeof(int) * 3 + calcMipmapSize(width, height, mipmapLevel) * comp;
                item.data.resize(item.length);
                *reinterpret_cast<int*>(item.data.data()) = width;
                *(reinterpret_cast<int*>(item.data.data()) + 1) = height;
                *(reinterpret_cast<int*>(item.data.data()) + 2) = mipmapLevel;
                std::memcpy(item.data.data() + sizeof(int) * 3, data, width*height*comp);
                stbi_image_free(data);
                int offset = generateMipmap(width, height, mipmapLevel, item.data.data() + sizeof(int) * 3);
            }
            else if (packFont && type == "Engine.Media.BitmapFont")
            {
                pack_bitmapFont(dirPathSafe, item);
            }
            else
            {
            pack_raw:
                std::string filePath = dirPathSafe + name;
                int fileSize = getFileSize(filePath.c_str());
                std::ifstream file(filePath, std::ios::binary);
                item.data.resize(fileSize);
                item.length = fileSize;
                file.read(reinterpret_cast<char*>(item.data.data()), fileSize);
                file.close();
            }
            pak.addItem(std::move(item));
            ++lineNumber;
        }
        fPakInfo.close();
        return pak;
    }

    int calcMipmapSize(int width, int height, int level)
    {
        if (level == 1)
            return width * height;
        if (!isPowerOfTwo(width) || !isPowerOfTwo(height))
            throw std::runtime_error("generating mipmaps for non-power of 2 images not supported");

        int size = width * height;
        while (width != 1 && height != 1 && level > 1)
        {
            width /= 2;
            height /= 2;
            --level;
            size += width * height;
        }
        if (width == 1 && height != 1)
            while (height != 1 && level > 1)
            {
                height /= 2;
                --level;
                size += width * height;
            }
        else if (height == 1 && width != 1)
            while (width != 1 && level > 1)
            {
                width /= 2;
                --level;
                size += width*height;
            }
        return size;
    }

    int generateMipmap(int width, int height, int level, unsigned char *image)
    {
        const int comp = 4;

        if (level == 1)
            return width * height * comp;
        if (!isPowerOfTwo(width) || !isPowerOfTwo(height))
            throw std::runtime_error("generating mipmaps for non-power of 2 images not supported");

        int offset = width * height * comp;
        int w=width, h=height;
        while (w != 1 && h%2 != 1 && level > 1)
        {
            w /= 2;
            h /= 2;
            --level;
            stbir_resize_uint8(image, width, height, 0,
                               image+offset, w, h, 0,
                               comp);
            offset += w * h * comp;
        }
        if (w == 1 && h != 1)
            while (h != 1 && level > 1)
            {
                h /= 2;
                --level;
                stbir_resize_uint8(image, width, height, 0,
                                   image + offset, w, h, 0,
                                   comp);
                offset += w * h * comp;
            }
        else if (h == 1 && w != 1)
            while (w != 1 && level > 1)
            {
                w /= 2;
                --level;
                stbir_resize_uint8(image, width, height, 0,
                                   image + offset, w, h, 0,
                                   comp);
                offset += w * h * comp;
            }
        return offset;
    }

    void unpack_string(const std::string &outputPath, const PakItem &item)
    {
        std::string fileName = outputPath + item.name;
        if (item.type == "System.String")
            fileName += ".txt";
        else if (item.type == "System.Xml.Linq.XElement")
            fileName += ".xml";
        else
            throw std::runtime_error("wrong item type");

        std::ofstream fout;
        fout.open(fileName, std::ios::binary);
        MemoryBinaryReader reader(item.data.data());
        std::string value = reader.readString();
        fout.write(value.data(), value.length());
        fout.close();
    }

    void pack_string(const std::string &inputPath, PakItem &item)
    {
        std::string fileName = inputPath + item.name;
        if (item.type == "System.String")
            fileName += ".txt";
        else if (item.type == "System.Xml.Linq.XElement")
            fileName += ".xml";
        else
            throw std::runtime_error("wrong item type");

        std::ifstream fin;
        fin.open(fileName, std::ios::binary);
        fin.seekg(0, std::ios::beg);
        int offsetBeg = fin.tellg();
        fin.seekg(0, std::ios::end);
        int offsetEnd = fin.tellg();
        int fileSize = offsetEnd - offsetBeg;
        fin.seekg(0, std::ios::beg);

        item.data.resize(fileSize+5);
        MemoryBinaryWriter writer(item.data.data());
        writer.write7BitEncodedInt(fileSize);
        item.length = fileSize + writer.position;
        fin.read(reinterpret_cast<char*>(item.data.data()+writer.position), fileSize);
        fin.close();
    }

    void unpack_bitmapFont(const std::string &outputDir, const PakItem &item)
    {
        std::string listFileName = outputDir + item.name + ".lst";
        std::string textureFileName = outputDir + item.name + ".tga";

        MemoryBinaryReader reader(item.data.data());
        int glyphCount = reader.readInt();
        std::vector<GlyphInfo> glyphList;
        glyphList.resize(glyphCount);
        for (int i = 0; i < glyphCount; ++i)
        {
            GlyphInfo &glyph = glyphList[i];
            glyph.unicode = reader.readUtf8Char();
            glyph.texCoord1.x = reader.readFloat();
            glyph.texCoord1.y = reader.readFloat();
            glyph.texCoord2.x = reader.readFloat();
            glyph.texCoord2.y = reader.readFloat();
            glyph.offset.x = reader.readFloat();
            glyph.offset.y = reader.readFloat();
            glyph.width = reader.readFloat();
        }
        float glyphHeight = reader.readFloat();
        Vector2f spacing;
        spacing.x = reader.readFloat();
        spacing.y = reader.readFloat();
        float scale = reader.readFloat();
        int fallbackCode = reader.readUtf8Char();

        int width = reader.readInt();
        int height = reader.readInt();
        int mipmapLevel = reader.readInt();

        stbi_write_tga(textureFileName.c_str(), width, height, 4, item.data.data() + reader.position);

        std::ofstream fList;
        fList.open(listFileName);
        fList << glyphCount << std::endl;
        for (int i = 0; i < glyphCount; ++i)
        {
            GlyphInfo &glyph = glyphList[i];
            fList << glyph.unicode << '\t'
                << glyph.texCoord1.x << '\t' << glyph.texCoord1.y << '\t'
                << glyph.texCoord2.x << '\t' << glyph.texCoord2.y << '\t'
                << glyph.offset.x << '\t' << glyph.offset.y << '\t'
                << glyph.width << std::endl;
        }
        fList << glyphHeight << std::endl;
        fList << spacing.x << '\t' << spacing.y << std::endl;
        fList << scale << std::endl;
        fList << fallbackCode << std::endl;
        fList.close();
    }

    void pack_bitmapFont(const std::string &inputDir, PakItem &item)
    {
        std::string listFileName = inputDir + item.name + ".lst";
        std::string textureFileName = inputDir + item.name + ".tga";

        std::ifstream fList;
        fList.open(listFileName);
        int glyphCount;
        fList >> glyphCount;

        int width, height, comp;
        unsigned char *data = stbi_load(textureFileName.c_str(), &width, &height, &comp, 4);
        item.data.resize(sizeof(GlyphInfo) * glyphCount + 50 + width*height * 4);

        MemoryBinaryWriter writer(item.data.data());
        writer.writeInt(glyphCount);
        for (int i = 0; i < glyphCount; ++i)
        {
            GlyphInfo glyph;
            fList >> glyph.unicode
                >> glyph.texCoord1.x >> glyph.texCoord1.y
                >> glyph.texCoord2.x >> glyph.texCoord2.y
                >> glyph.offset.x >> glyph.offset.y
                >> glyph.width;
            writer.writeUtf8Char(glyph.unicode);
            writer.writeFloat(glyph.texCoord1.x);
            writer.writeFloat(glyph.texCoord1.y);
            writer.writeFloat(glyph.texCoord2.x);
            writer.writeFloat(glyph.texCoord2.y);
            writer.writeFloat(glyph.offset.x);
            writer.writeFloat(glyph.offset.y);
            writer.writeFloat(glyph.width);
        }
        float glyphHeight; fList >> glyphHeight;
        Vector2f spacing; fList >> spacing.x >> spacing.y;
        float scale; fList >> scale;
        int fallbackCode; fList >> fallbackCode;
        writer.writeFloat(glyphHeight);
        writer.writeFloat(spacing.x);
        writer.writeFloat(spacing.y);
        writer.writeFloat(scale);
        writer.writeUtf8Char(fallbackCode);
        fList.close();

        writer.writeInt(width);
        writer.writeInt(height);
        writer.writeInt(1);
        std::memcpy(item.data.data() + writer.position, data, width*height * 4);
        item.length = writer.position + width*height * 4;

        stbi_image_free(data);
    }

    bool isPowerOfTwo(int n)
    {
        return (n & (n - 1)) == 0;
    }
}

<|endoftext|>