<commit_before>// Scintilla source code edit control
/** @file AutoComplete.cxx
 ** Defines the auto completion list box.
 **/
// Copyright 1998-2001 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 <stdio.h>

#include "Platform.h"

#include "PropSet.h"
#include "AutoComplete.h"

AutoComplete::AutoComplete() :
	active(false),
	separator(' '),
	ignoreCase(false),
	chooseSingle(false),
	posStart(0),
	startLen(0),
	cancelAtStartPos(true),
	autoHide(true) {
	stopChars[0] = '\0';
	fillUpChars[0] = '\0';
}

AutoComplete::~AutoComplete() {
	lb.Destroy();
}

bool AutoComplete::Active() {
	return active;
}

void AutoComplete::Start(Window &parent, int ctrlID, int position, int startLen_) {
	if (!lb.Created()) {
		lb.Create(parent, ctrlID);
	}
	lb.Clear();
	active = true;
	startLen = startLen_;
	posStart = position;
}

void AutoComplete::SetStopChars(const char *stopChars_) {
	strncpy(stopChars, stopChars_, sizeof(stopChars));
	stopChars[sizeof(stopChars) - 1] = '\0';
}

bool AutoComplete::IsStopChar(char ch) {
	return ch && strchr(stopChars, ch);
}

void AutoComplete::SetFillUpChars(const char *fillUpChars_) {
	strncpy(fillUpChars, fillUpChars_, sizeof(fillUpChars));
	fillUpChars[sizeof(fillUpChars) - 1] = '\0';
}

bool AutoComplete::IsFillUpChar(char ch) {
	return ch && strchr(fillUpChars, ch);
}

void AutoComplete::SetSeparator(char separator_) {
	separator = separator_;
}

char AutoComplete::GetSeparator() {
	return separator;
}

void AutoComplete::SetList(const char *list) {
	lb.Clear();
	char *words = new char[strlen(list) + 1];
	if (words) {
		strcpy(words, list);
		char *startword = words;
		int i = 0;
		for (; words && words[i]; i++) {
			if (words[i] == separator) {
				words[i] = '\0';
				lb.Append(startword);
				startword = words + i + 1;
			}
		}
		if (startword) {
			lb.Append(startword);
		}
		delete []words;
	}
	//lb.Sort();
}

void AutoComplete::Show() {
	lb.Show();
	lb.Select(0);
}

void AutoComplete::Cancel() {
	if (lb.Created()) {
		lb.Destroy();
		active = false;
	}
}

void AutoComplete::Move(int delta) {
	int count = lb.Length();
	int current = lb.GetSelection();
	current += delta;
	if (current >= count)
		current = count - 1;
	if (current < 0)
		current = 0;
	lb.Select(current);
}

void AutoComplete::Select(const char *word) {
	int lenWord = strlen(word);
	int location = -1;
	const int maxItemLen=1000;
	char item[maxItemLen];
	int start = 0; // lower bound of the api array block to search
	int end = lb.Length() - 1; // upper bound of the api array block to search
	while ((start <= end) && (location == -1)) { // Binary searching loop
		int pivot = (start + end) / 2;
		lb.GetValue(pivot, item, maxItemLen);
		int cond = 0;
		if (ignoreCase)
			cond = CompareNCaseInsensitive(word, item, lenWord);
		else
			cond = strncmp(word, item, lenWord);
		if (!cond) {
			// Find first match
			while (pivot > start) {
				lb.GetValue(pivot-1, item, maxItemLen);
				if (ignoreCase)
					cond = CompareNCaseInsensitive(word, item, lenWord);
				else
					cond = strncmp(word, item, lenWord);
				if (0 != cond)
					break;
				--pivot;
			}
			location = pivot;
		} else if (cond < 0) {
			end = pivot - 1;
		} else if (cond > 0) {
			start = pivot + 1;
		}
	}
	if (location == -1 && autoHide)
		Cancel();
	else
		lb.Select(location);
}

<commit_msg>Removed commented out call to sort list as list is always in correct order now.<commit_after>// Scintilla source code edit control
/** @file AutoComplete.cxx
 ** Defines the auto completion list box.
 **/
// Copyright 1998-2001 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 <stdio.h>

#include "Platform.h"

#include "PropSet.h"
#include "AutoComplete.h"

AutoComplete::AutoComplete() :
	active(false),
	separator(' '),
	ignoreCase(false),
	chooseSingle(false),
	posStart(0),
	startLen(0),
	cancelAtStartPos(true),
	autoHide(true) {
	stopChars[0] = '\0';
	fillUpChars[0] = '\0';
}

AutoComplete::~AutoComplete() {
	lb.Destroy();
}

bool AutoComplete::Active() {
	return active;
}

void AutoComplete::Start(Window &parent, int ctrlID, int position, int startLen_) {
	if (!lb.Created()) {
		lb.Create(parent, ctrlID);
	}
	lb.Clear();
	active = true;
	startLen = startLen_;
	posStart = position;
}

void AutoComplete::SetStopChars(const char *stopChars_) {
	strncpy(stopChars, stopChars_, sizeof(stopChars));
	stopChars[sizeof(stopChars) - 1] = '\0';
}

bool AutoComplete::IsStopChar(char ch) {
	return ch && strchr(stopChars, ch);
}

void AutoComplete::SetFillUpChars(const char *fillUpChars_) {
	strncpy(fillUpChars, fillUpChars_, sizeof(fillUpChars));
	fillUpChars[sizeof(fillUpChars) - 1] = '\0';
}

bool AutoComplete::IsFillUpChar(char ch) {
	return ch && strchr(fillUpChars, ch);
}

void AutoComplete::SetSeparator(char separator_) {
	separator = separator_;
}

char AutoComplete::GetSeparator() {
	return separator;
}

void AutoComplete::SetList(const char *list) {
	lb.Clear();
	char *words = new char[strlen(list) + 1];
	if (words) {
		strcpy(words, list);
		char *startword = words;
		int i = 0;
		for (; words && words[i]; i++) {
			if (words[i] == separator) {
				words[i] = '\0';
				lb.Append(startword);
				startword = words + i + 1;
			}
		}
		if (startword) {
			lb.Append(startword);
		}
		delete []words;
	}
}

void AutoComplete::Show() {
	lb.Show();
	lb.Select(0);
}

void AutoComplete::Cancel() {
	if (lb.Created()) {
		lb.Destroy();
		active = false;
	}
}

void AutoComplete::Move(int delta) {
	int count = lb.Length();
	int current = lb.GetSelection();
	current += delta;
	if (current >= count)
		current = count - 1;
	if (current < 0)
		current = 0;
	lb.Select(current);
}

void AutoComplete::Select(const char *word) {
	int lenWord = strlen(word);
	int location = -1;
	const int maxItemLen=1000;
	char item[maxItemLen];
	int start = 0; // lower bound of the api array block to search
	int end = lb.Length() - 1; // upper bound of the api array block to search
	while ((start <= end) && (location == -1)) { // Binary searching loop
		int pivot = (start + end) / 2;
		lb.GetValue(pivot, item, maxItemLen);
		int cond = 0;
		if (ignoreCase)
			cond = CompareNCaseInsensitive(word, item, lenWord);
		else
			cond = strncmp(word, item, lenWord);
		if (!cond) {
			// Find first match
			while (pivot > start) {
				lb.GetValue(pivot-1, item, maxItemLen);
				if (ignoreCase)
					cond = CompareNCaseInsensitive(word, item, lenWord);
				else
					cond = strncmp(word, item, lenWord);
				if (0 != cond)
					break;
				--pivot;
			}
			location = pivot;
		} else if (cond < 0) {
			end = pivot - 1;
		} else if (cond > 0) {
			start = pivot + 1;
		}
	}
	if (location == -1 && autoHide)
		Cancel();
	else
		lb.Select(location);
}

<|endoftext|>


<commit_before>#include "fastfilters.hxx"

namespace fastfilters
{

namespace iir
{
void convolve_iir_inner_single(const float *input, const unsigned int n_pixels, const unsigned n_times, float *output,
                               const Coefficients &coefs)
{
    if (detail::cpu_has_avx2())
        convolve_iir_inner_single_avx(input, n_pixels, n_times, output, coefs);
    else
        convolve_iir_inner_single_noavx(input, n_pixels, n_times, output, coefs);
}

void convolve_iir_outer_single(const float *input, const unsigned int n_pixels, const unsigned n_times, float *output,
                               const Coefficients &coefs)
{
    if (detail::cpu_has_avx2())
        convolve_iir_outer_single_avx(input, n_pixels, n_times, output, coefs);
    else
        convolve_iir_outer_single_noavx(input, n_pixels, n_times, output, coefs, n_times);
}

} // namepsace iir

} // namespace fastfilters<commit_msg>add missing license header<commit_after>// fastfilters
// Copyright (c) 2016 Sven Peter
// sven.peter@iwr.uni-heidelberg.de or mail@svenpeter.me
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
// Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
#include "fastfilters.hxx"

namespace fastfilters
{

namespace iir
{
void convolve_iir_inner_single(const float *input, const unsigned int n_pixels, const unsigned n_times, float *output,
                               const Coefficients &coefs)
{
    if (detail::cpu_has_avx2())
        convolve_iir_inner_single_avx(input, n_pixels, n_times, output, coefs);
    else
        convolve_iir_inner_single_noavx(input, n_pixels, n_times, output, coefs);
}

void convolve_iir_outer_single(const float *input, const unsigned int n_pixels, const unsigned n_times, float *output,
                               const Coefficients &coefs)
{
    if (detail::cpu_has_avx2())
        convolve_iir_outer_single_avx(input, n_pixels, n_times, output, coefs);
    else
        convolve_iir_outer_single_noavx(input, n_pixels, n_times, output, coefs, n_times);
}

} // namepsace iir

} // namespace fastfilters<|endoftext|>


<commit_before>
/**
 * @file CodeSmoother.hpp
 * This class smoothes a given code observable using the corresponding phase observable.
 */

#ifndef CODE_SMOOTHER_GPSTK
#define CODE_SMOOTHER_GPSTK

//============================================================================
//
//  This file is part of GPSTk, the GPS Toolkit.
//
//  The GPSTk is free software; you can redistribute it and/or modify
//  it under the terms of the GNU Lesser General Public License as published
//  by the Free Software Foundation; either version 2.1 of the License, or
//  any later version.
//
//  The GPSTk 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 for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with GPSTk; if not, write to the Free Software Foundation,
//  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Dagoberto Salazar - gAGE ( http://www.gage.es ). 2007
//
//============================================================================

#include "DataStructures.hpp"

namespace gpstk
{

    /** @addtogroup DataStructures */
    //@{

    /** This class smoothes a given code observable using the corresponding phase observable.
     * This class is meant to be used with the GNSS data structures objects
     * found in "DataStructures" class.
     *
     * A typical way to use this class follows:
     *
     * @code
     *   RinexObsStream rin("ebre0300.02o");
     *
     *   gnssRinex gRin;
     *   OneFreqCSDetector markCSC1;    // We MUST mark cycle slips
     *   CodeSmoother smoothC1;
     *
     *   while(rin >> gRin) {
     *      gRin >> markCSC1 >> smoothC1;
     *   }
     * @endcode
     *
     * The "CodeSmoother" object will visit every satellite in the GNSS data
     * structure that is "gRin" and will smooth the given code observation using
     * the corresponding phase observation.
     *
     * By default, the algorithm will use C1 and L1 observables, and the CSL1 index
     * will be consulted for cycle slip information. You can change these settings
     * with the appropriate set methods.
     *
     * When used with the ">>" operator, this class returns the same incoming
     * data structure with the code observation smoothed (unless the resultType
     * field is changed). Be warned that if a given satellite does not have the
     * observations required, it will be summarily deleted from the data
     * structure.
     *
     * Another important parameter is the maxWindowSize field. By default, it is
     * set to 100 samples (you may adjust that with the setMaxWindowSize() method).
     *
     * A window of 100 samples is typical and appropriate when working with data
     * sampled at 1 Hz, because then the full window will last at most 100 seconds.
     *
     * However, if for instance your samples are taken at 30 seconds (and you are
     * working with C1/L1 or other ionosphere-affected observation pair), then a
     * window of 50 minutes will be used and you will get badly distorted data
     * because of ionosphere drift, among other effects.
     *
     * A good rule here is to make sure that the filter window lasts at most 5 minutes.
     * Therefore, for a 30 s sampling data set you should set your smoother object like
     * this:
     *
     * @code
     *   CodeSmoother smoothC1;
     *   smoothC1.setMaxWindowSize(8);
     * @endcode
     *
     * Resulting in a 4 minutes filter window.
     *
     * \warning Code smoothers are objets that store their internal state,
     * so you MUST NOT use the SAME object to process DIFFERENT data streams.
     *
     */
    class CodeSmoother
    {
    public:

        /// Default constructor, setting default parameters and C1 and L1 as observables.
        CodeSmoother() : codeType(TypeID::C1), phaseType(TypeID::L1), resultType(TypeID::C1), maxWindowSize(100), csFlag(TypeID::CSL1) { };

        /** Common constructor
         *
         * @param codeT         Type of code to be smoothed.
         * @param mwSize        Maximum  size of filter window, in samples.
         */
        CodeSmoother(const TypeID& codeT, const int& mwSize = 100) : codeType(codeT)
        {
            // Don't allow window sizes less than 1
            if (mwSize > 1) maxWindowSize = mwSize; else maxWindowSize = 1;

            switch ( codeT.type )
            {
                case TypeID::C1:
                    phaseType   = TypeID::L1;
                    csFlag      = TypeID::CSL1;
                    resultType  = TypeID::C1;
                    break;
                case TypeID::C2:
                    phaseType   = TypeID::L2;
                    csFlag      = TypeID::CSL2;
                    resultType  = TypeID::C2;
                    break;
                case TypeID::C5:
                    phaseType   = TypeID::L5;
                    csFlag      = TypeID::CSL5;
                    resultType  = TypeID::C5;
                    break;
                case TypeID::C6:
                    phaseType   = TypeID::L6;
                    csFlag      = TypeID::CSL6;
                    resultType  = TypeID::C6;
                    break;
                case TypeID::C7:
                    phaseType   = TypeID::L7;
                    csFlag      = TypeID::CSL7;
                    resultType  = TypeID::C7;
                    break;
                case TypeID::C8:
                    phaseType   = TypeID::L8;
                    csFlag      = TypeID::CSL8;
                    resultType  = TypeID::C8;
                    break;
                default:
                    phaseType   = TypeID::L1;
                    csFlag      = TypeID::CSL1;
                    resultType  = TypeID::C1;
                };
        };

        /** Returns a satTypeValueMap object, adding the new data generated when calling this object.
         *
         * @param gData     Data object holding the data.
         */
        virtual satTypeValueMap& Smooth(satTypeValueMap& gData)
        {
            double codeObs(0.0);
            double phaseObs(0.0);
            double flagObs(0.0);

            SatIDSet satRejectedSet;

            // Loop through all the satellites
            satTypeValueMap::iterator it;
            for (it = gData.begin(); it != gData.end(); ++it)
            {
                try
                {
                    // Try to extract the values
                    codeObs  = (*it).second(codeType);
                    phaseObs = (*it).second(phaseType);
                    flagObs  = (*it).second(csFlag);
                }
                catch(...)
                {
                    // If some value is missing, then schedule this satellite for removal
                    satRejectedSet.insert( (*it).first );
                    continue;
                }
                // If everything is OK, then process according if there is a cycle slip or not.
                (*it).second[resultType] = getSmoothing((*it).first, codeObs, phaseObs, flagObs);
            }
            // Remove satellites with missing data
            gData.removeSatID(satRejectedSet);

            return gData;
        };

        /** Returns a gnnsSatTypeValue object, adding the new data generated when calling this object.
         *
         * @param gData    Data object holding the data.
         */
        virtual gnssSatTypeValue& Smooth(gnssSatTypeValue& gData)
        {
            (*this).Smooth(gData.body);
            return gData;
        };

        /** Returns a gnnsRinex object, adding the new data generated when calling this object.
         *
         * @param gData    Data object holding the data.
         */
        virtual gnssRinex& Smooth(gnssRinex& gData)
        {
            (*this).Smooth(gData.body);
            return gData;
        };

        /** Method to set the default code type to be used.
         * @param codeT     TypeID of code to be used
         */
        virtual void setCodeType(const TypeID& codeT)
        {
           codeType = codeT;
        };

        /// Method to get the default code type being used.
        virtual TypeID getCodeType() const
        {
           return codeType;
        };

        /** Method to set the default phase type to be used.
         * @param phaseT    TypeID of phase to be used
         */
        virtual void setPhaseType(const TypeID& phaseT)
        {
           phaseType = phaseT;
        };

        /// Method to get the default phase type being used.
        virtual TypeID getPhaseType() const
        {
           return phaseType;
        };

        /** Method to set the default cycle slip type to be used.
         * @param csT   Cycle slip type to be used
         */
        virtual void setCSFlag(const TypeID& csT)
        {
           csFlag = csT;
        };

        /// Method to get the default cycle slip type being used.
        virtual TypeID getCSFlag() const
        {
           return csFlag;
        };

        /** Method to set the default return type to be used.
         * @param returnT    TypeID to be returned
         */
        virtual void setResultType(const TypeID& resultT)
        {
           resultType = resultT;
        };

        /// Method to get the default return type being used.
        virtual TypeID getResultType() const
        {
           return resultType;
        };

        /** Method to set the maximum size of filter window, in samples.
         * @param maxSize       Maximum size of filter window, in samples.
         */
        virtual void setMaxWindowSize(const int& maxSize)
        {
            // Don't allow window sizes less than 1
            if (maxSize > 1) maxWindowSize = maxSize; else maxWindowSize = 1;
        };

        /// Method to get the maximum size of filter window, in samples.
        virtual int getMaxWindowSize() const
        {
           return maxWindowSize;
        };

        /// Destructor
        virtual ~CodeSmoother() {};

    private:

        /// Type of code observation to be used.
        TypeID codeType;

        /// Type of phase observation to be used.
        TypeID phaseType;

        /// Type assigned to the resulting smoothed code.
        TypeID resultType;

        /// Maximum size of filter window, in samples.
        int maxWindowSize;

        /// Cycle slip flag. It MUST be present. @sa OneFreqCSDetector.hpp class.
        TypeID csFlag;

        /// A structure used to store filter data for a SV.
        struct filterData
        {
            // Default constructor initializing the data in the structure
            filterData() : windowSize(1), previousCode(0.0), previousPhase(0.0) {};

            int windowSize;         ///< The filter window size.
            double previousCode;        ///< Accumulated mean bias (pseudorange - phase).
            double previousPhase;      ///< Accumulated mean bias sigma squared.
        };

        /// Map holding the information regarding every satellite
        std::map<SatID, filterData> SmoothingData;

        /// Compute the combination of observables.
        virtual double getSmoothing(const SatID& sat, const double& code, const double& phase, const double& flag)
        {
            if ( flag!=0.0 )  // In case we have a cycle slip
            {
                // Prepare the structure for the next iteration
                SmoothingData[sat].previousCode = code;
                SmoothingData[sat].previousPhase = phase;
                SmoothingData[sat].windowSize = 1;
                return code;    // We don't need any further processing
            }

            // In case we didn't have cycle slip
            double smoothedCode(0.0);

            // Increment size of window and check limit
            ++SmoothingData[sat].windowSize;
            if (SmoothingData[sat].windowSize > maxWindowSize) SmoothingData[sat].windowSize = maxWindowSize;

            // The formula used is the following:
            //
            // CSn = (1/n)*Cn + ((n-1)/n)*(CSn-1 + Ln - Ln-1)
            //
            // As window size "n" increases, the former formula gives more
            // weight to the previous smoothed code CSn-1 plus the phase bias
            // (Ln - Ln-1), and less weight to the current code observation Cn
            smoothedCode = ( code + ((static_cast<double>(SmoothingData[sat].windowSize)) - 1.0) * (SmoothingData[sat].previousCode + (phase - SmoothingData[sat].previousPhase) ) ) / (static_cast<double>(SmoothingData[sat].windowSize));

            // Store results for next iteration
            SmoothingData[sat].previousCode = smoothedCode;
            SmoothingData[sat].previousPhase = phase;

            return smoothedCode;
        };

   }; // end class CodeSmoother

    /// Input operator from gnssSatTypeValue to CodeSmoother.
    inline gnssSatTypeValue& operator>>(gnssSatTypeValue& gData, CodeSmoother& codeS)
    {
            codeS.Smooth(gData);
            return gData;
    }

    /// Input operator from gnssRinex to CodeSmoother.
    inline gnssRinex& operator>>(gnssRinex& gData, CodeSmoother& codeS)
    {
            codeS.Smooth(gData);
            return gData;
    }

   //@}

}

#endif
<commit_msg>Added P1 and P2 to the constructor's auto configuration list.<commit_after>
/**
 * @file CodeSmoother.hpp
 * This class smoothes a given code observable using the corresponding phase observable.
 */

#ifndef CODE_SMOOTHER_GPSTK
#define CODE_SMOOTHER_GPSTK

//============================================================================
//
//  This file is part of GPSTk, the GPS Toolkit.
//
//  The GPSTk is free software; you can redistribute it and/or modify
//  it under the terms of the GNU Lesser General Public License as published
//  by the Free Software Foundation; either version 2.1 of the License, or
//  any later version.
//
//  The GPSTk 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 for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with GPSTk; if not, write to the Free Software Foundation,
//  Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//  Dagoberto Salazar - gAGE ( http://www.gage.es ). 2007
//
//============================================================================

#include "DataStructures.hpp"

namespace gpstk
{

    /** @addtogroup DataStructures */
    //@{

    /** This class smoothes a given code observable using the corresponding phase observable.
     * This class is meant to be used with the GNSS data structures objects
     * found in "DataStructures" class.
     *
     * A typical way to use this class follows:
     *
     * @code
     *   RinexObsStream rin("ebre0300.02o");
     *
     *   gnssRinex gRin;
     *   OneFreqCSDetector markCSC1;    // We MUST mark cycle slips
     *   CodeSmoother smoothC1;
     *
     *   while(rin >> gRin) {
     *      gRin >> markCSC1 >> smoothC1;
     *   }
     * @endcode
     *
     * The "CodeSmoother" object will visit every satellite in the GNSS data
     * structure that is "gRin" and will smooth the given code observation using
     * the corresponding phase observation.
     *
     * By default, the algorithm will use C1 and L1 observables, and the CSL1 index
     * will be consulted for cycle slip information. You can change these settings
     * with the appropriate set methods.
     *
     * When used with the ">>" operator, this class returns the same incoming
     * data structure with the code observation smoothed (unless the resultType
     * field is changed). Be warned that if a given satellite does not have the
     * observations required, it will be summarily deleted from the data
     * structure.
     *
     * Another important parameter is the maxWindowSize field. By default, it is
     * set to 100 samples (you may adjust that with the setMaxWindowSize() method).
     *
     * A window of 100 samples is typical and appropriate when working with data
     * sampled at 1 Hz, because then the full window will last at most 100 seconds.
     *
     * However, if for instance your samples are taken at 30 seconds (and you are
     * working with C1/L1 or other ionosphere-affected observation pair), then a
     * window of 50 minutes will be used and you will get badly distorted data
     * because of ionosphere drift, among other effects.
     *
     * A good rule here is to make sure that the filter window lasts at most 5 minutes.
     * Therefore, for a 30 s sampling data set you should set your smoother object like
     * this:
     *
     * @code
     *   CodeSmoother smoothC1;
     *   smoothC1.setMaxWindowSize(8);
     * @endcode
     *
     * Resulting in a 4 minutes filter window.
     *
     * \warning Code smoothers are objets that store their internal state,
     * so you MUST NOT use the SAME object to process DIFFERENT data streams.
     *
     */
    class CodeSmoother
    {
    public:

        /// Default constructor, setting default parameters and C1 and L1 as observables.
        CodeSmoother() : codeType(TypeID::C1), phaseType(TypeID::L1), resultType(TypeID::C1), maxWindowSize(100), csFlag(TypeID::CSL1) { };

        /** Common constructor
         *
         * @param codeT         Type of code to be smoothed.
         * @param mwSize        Maximum  size of filter window, in samples.
         */
        CodeSmoother(const TypeID& codeT, const int& mwSize = 100) : codeType(codeT)
        {
            // Don't allow window sizes less than 1
            if (mwSize > 1) maxWindowSize = mwSize; else maxWindowSize = 1;

            switch ( codeT.type )
            {
                case TypeID::C1:
                    phaseType   = TypeID::L1;
                    csFlag      = TypeID::CSL1;
                    resultType  = TypeID::C1;
                    break;
                case TypeID::C2:
                    phaseType   = TypeID::L2;
                    csFlag      = TypeID::CSL2;
                    resultType  = TypeID::C2;
                    break;
                case TypeID::P1:
                    phaseType   = TypeID::L1;
                    csFlag      = TypeID::CSL1;
                    resultType  = TypeID::P1;
                    break;
                case TypeID::P2:
                    phaseType   = TypeID::L2;
                    csFlag      = TypeID::CSL2;
                    resultType  = TypeID::P2;
                    break;
                case TypeID::C5:
                    phaseType   = TypeID::L5;
                    csFlag      = TypeID::CSL5;
                    resultType  = TypeID::C5;
                    break;
                case TypeID::C6:
                    phaseType   = TypeID::L6;
                    csFlag      = TypeID::CSL6;
                    resultType  = TypeID::C6;
                    break;
                case TypeID::C7:
                    phaseType   = TypeID::L7;
                    csFlag      = TypeID::CSL7;
                    resultType  = TypeID::C7;
                    break;
                case TypeID::C8:
                    phaseType   = TypeID::L8;
                    csFlag      = TypeID::CSL8;
                    resultType  = TypeID::C8;
                    break;
                default:
                    phaseType   = TypeID::L1;
                    csFlag      = TypeID::CSL1;
                    resultType  = TypeID::C1;
                };
        };

        /** Returns a satTypeValueMap object, adding the new data generated when calling this object.
         *
         * @param gData     Data object holding the data.
         */
        virtual satTypeValueMap& Smooth(satTypeValueMap& gData)
        {
            double codeObs(0.0);
            double phaseObs(0.0);
            double flagObs(0.0);

            SatIDSet satRejectedSet;

            // Loop through all the satellites
            satTypeValueMap::iterator it;
            for (it = gData.begin(); it != gData.end(); ++it)
            {
                try
                {
                    // Try to extract the values
                    codeObs  = (*it).second(codeType);
                    phaseObs = (*it).second(phaseType);
                    flagObs  = (*it).second(csFlag);
                }
                catch(...)
                {
                    // If some value is missing, then schedule this satellite for removal
                    satRejectedSet.insert( (*it).first );
                    continue;
                }
                // If everything is OK, then process according if there is a cycle slip or not.
                (*it).second[resultType] = getSmoothing((*it).first, codeObs, phaseObs, flagObs);
            }
            // Remove satellites with missing data
            gData.removeSatID(satRejectedSet);

            return gData;
        };

        /** Returns a gnnsSatTypeValue object, adding the new data generated when calling this object.
         *
         * @param gData    Data object holding the data.
         */
        virtual gnssSatTypeValue& Smooth(gnssSatTypeValue& gData)
        {
            (*this).Smooth(gData.body);
            return gData;
        };

        /** Returns a gnnsRinex object, adding the new data generated when calling this object.
         *
         * @param gData    Data object holding the data.
         */
        virtual gnssRinex& Smooth(gnssRinex& gData)
        {
            (*this).Smooth(gData.body);
            return gData;
        };

        /** Method to set the default code type to be used.
         * @param codeT     TypeID of code to be used
         */
        virtual void setCodeType(const TypeID& codeT)
        {
           codeType = codeT;
        };

        /// Method to get the default code type being used.
        virtual TypeID getCodeType() const
        {
           return codeType;
        };

        /** Method to set the default phase type to be used.
         * @param phaseT    TypeID of phase to be used
         */
        virtual void setPhaseType(const TypeID& phaseT)
        {
           phaseType = phaseT;
        };

        /// Method to get the default phase type being used.
        virtual TypeID getPhaseType() const
        {
           return phaseType;
        };

        /** Method to set the default cycle slip type to be used.
         * @param csT   Cycle slip type to be used
         */
        virtual void setCSFlag(const TypeID& csT)
        {
           csFlag = csT;
        };

        /// Method to get the default cycle slip type being used.
        virtual TypeID getCSFlag() const
        {
           return csFlag;
        };

        /** Method to set the default return type to be used.
         * @param returnT    TypeID to be returned
         */
        virtual void setResultType(const TypeID& resultT)
        {
           resultType = resultT;
        };

        /// Method to get the default return type being used.
        virtual TypeID getResultType() const
        {
           return resultType;
        };

        /** Method to set the maximum size of filter window, in samples.
         * @param maxSize       Maximum size of filter window, in samples.
         */
        virtual void setMaxWindowSize(const int& maxSize)
        {
            // Don't allow window sizes less than 1
            if (maxSize > 1) maxWindowSize = maxSize; else maxWindowSize = 1;
        };

        /// Method to get the maximum size of filter window, in samples.
        virtual int getMaxWindowSize() const
        {
           return maxWindowSize;
        };

        /// Destructor
        virtual ~CodeSmoother() {};

    private:

        /// Type of code observation to be used.
        TypeID codeType;

        /// Type of phase observation to be used.
        TypeID phaseType;

        /// Type assigned to the resulting smoothed code.
        TypeID resultType;

        /// Maximum size of filter window, in samples.
        int maxWindowSize;

        /// Cycle slip flag. It MUST be present. @sa OneFreqCSDetector.hpp class.
        TypeID csFlag;

        /// A structure used to store filter data for a SV.
        struct filterData
        {
            // Default constructor initializing the data in the structure
            filterData() : windowSize(1), previousCode(0.0), previousPhase(0.0) {};

            int windowSize;         ///< The filter window size.
            double previousCode;        ///< Accumulated mean bias (pseudorange - phase).
            double previousPhase;      ///< Accumulated mean bias sigma squared.
        };

        /// Map holding the information regarding every satellite
        std::map<SatID, filterData> SmoothingData;

        /// Compute the combination of observables.
        virtual double getSmoothing(const SatID& sat, const double& code, const double& phase, const double& flag)
        {
            if ( flag!=0.0 )  // In case we have a cycle slip
            {
                // Prepare the structure for the next iteration
                SmoothingData[sat].previousCode = code;
                SmoothingData[sat].previousPhase = phase;
                SmoothingData[sat].windowSize = 1;
                return code;    // We don't need any further processing
            }

            // In case we didn't have cycle slip
            double smoothedCode(0.0);

            // Increment size of window and check limit
            ++SmoothingData[sat].windowSize;
            if (SmoothingData[sat].windowSize > maxWindowSize) SmoothingData[sat].windowSize = maxWindowSize;

            // The formula used is the following:
            //
            // CSn = (1/n)*Cn + ((n-1)/n)*(CSn-1 + Ln - Ln-1)
            //
            // As window size "n" increases, the former formula gives more
            // weight to the previous smoothed code CSn-1 plus the phase bias
            // (Ln - Ln-1), and less weight to the current code observation Cn
            smoothedCode = ( code + ((static_cast<double>(SmoothingData[sat].windowSize)) - 1.0) * (SmoothingData[sat].previousCode + (phase - SmoothingData[sat].previousPhase) ) ) / (static_cast<double>(SmoothingData[sat].windowSize));

            // Store results for next iteration
            SmoothingData[sat].previousCode = smoothedCode;
            SmoothingData[sat].previousPhase = phase;

            return smoothedCode;
        };

   }; // end class CodeSmoother

    /// Input operator from gnssSatTypeValue to CodeSmoother.
    inline gnssSatTypeValue& operator>>(gnssSatTypeValue& gData, CodeSmoother& codeS)
    {
            codeS.Smooth(gData);
            return gData;
    }

    /// Input operator from gnssRinex to CodeSmoother.
    inline gnssRinex& operator>>(gnssRinex& gData, CodeSmoother& codeS)
    {
            codeS.Smooth(gData);
            return gData;
    }

   //@}

}

#endif
<|endoftext|>


<commit_before>/*
 * Copyright 2012 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkRRect.h"

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

void SkRRect::setRectXY(const SkRect& rect, SkScalar xRad, SkScalar yRad) {
    if (rect.isEmpty()) {
        this->setEmpty();
        return;
    }

    if (xRad <= 0 || yRad <= 0) {
        // all corners are square in this case
        this->setRect(rect);
        return;
    }

    if (rect.width() < xRad+xRad || rect.height() < yRad+yRad) {
        SkScalar scale = SkMinScalar(SkScalarDiv(rect.width(), xRad + xRad),
                                     SkScalarDiv(rect.height(), yRad + yRad));
        SkASSERT(scale < SK_Scalar1);
        xRad = SkScalarMul(xRad, scale);
        yRad = SkScalarMul(yRad, scale);
    }

    fRect = rect;
    for (int i = 0; i < 4; ++i) {
        fRadii[i].set(xRad, yRad);
    }
    fType = kSimple_Type;
    if (xRad >= SkScalarHalf(fRect.width()) && yRad >= SkScalarHalf(fRect.height())) {
        fType = kOval_Type;
        // TODO: try asserting they are already W/2 & H/2 already
        xRad = SkScalarHalf(fRect.width());
        yRad = SkScalarHalf(fRect.height());
    }

    SkDEBUGCODE(this->validate();)
}

void SkRRect::setRectRadii(const SkRect& rect, const SkVector radii[4]) {
    if (rect.isEmpty()) {
        this->setEmpty();
        return;
    }

    fRect = rect;
    memcpy(fRadii, radii, sizeof(fRadii));

    bool allCornersSquare = true;

    // Clamp negative radii to zero
    for (int i = 0; i < 4; ++i) {
        if (fRadii[i].fX <= 0 || fRadii[i].fY <= 0) {
            // In this case we are being a little fast & loose. Since one of
            // the radii is 0 the corner is square. However, the other radii
            // could still be non-zero and play in the global scale factor
            // computation.
            fRadii[i].fX = 0;
            fRadii[i].fY = 0;
        } else {
            allCornersSquare = false;
        }
    }

    if (allCornersSquare) {
        this->setRect(rect);
        return;
    }

    // Proportionally scale down all radii to fit. Find the minimum ratio
    // of a side and the radii on that side (for all four sides) and use
    // that to scale down _all_ the radii. This algorithm is from the
    // W3 spec (http://www.w3.org/TR/css3-background/) section 5.5 - Overlapping
    // Curves:
    // "Let f = min(Li/Si), where i is one of { top, right, bottom, left },
    //   Si is the sum of the two corresponding radii of the corners on side i,
    //   and Ltop = Lbottom = the width of the box,
    //   and Lleft = Lright = the height of the box.
    // If f < 1, then all corner radii are reduced by multiplying them by f."
    SkScalar scale = SK_Scalar1;

    if (fRadii[0].fX + fRadii[1].fX > rect.width()) {
        scale = SkMinScalar(scale,
                            SkScalarDiv(rect.width(), fRadii[0].fX + fRadii[1].fX));
    }
    if (fRadii[1].fY + fRadii[2].fY > rect.height()) {
        scale = SkMinScalar(scale,
                            SkScalarDiv(rect.height(), fRadii[1].fY + fRadii[2].fY));
    }
    if (fRadii[2].fX + fRadii[3].fX > rect.width()) {
        scale = SkMinScalar(scale,
                            SkScalarDiv(rect.width(), fRadii[2].fX + fRadii[3].fX));
    }
    if (fRadii[3].fY + fRadii[0].fY > rect.height()) {
        scale = SkMinScalar(scale,
                            SkScalarDiv(rect.height(), fRadii[3].fY + fRadii[0].fY));
    }

    if (scale < SK_Scalar1) {
        for (int i = 0; i < 4; ++i) {
            fRadii[i].fX = SkScalarMul(fRadii[i].fX, scale);
            fRadii[i].fY = SkScalarMul(fRadii[i].fY, scale);
        }
    }

    // At this point we're either oval, simple, or complex (not empty or rect)
    // but we lazily resolve the type to avoid the work if the information
    // isn't required.
    fType = (SkRRect::Type) kUnknown_Type;

    SkDEBUGCODE(this->validate();)
}

bool SkRRect::contains(SkScalar x, SkScalar y) const {
    SkDEBUGCODE(this->validate();)

    if (kEmpty_Type == this->type()) {
        return false;
    }

    if (!fRect.contains(x, y)) {
        return false;
    }

    if (kRect_Type == this->type()) {
        // the 'fRect' test above was sufficient
        return true;
    }

    // We know the point is inside the RR's bounds. The only way it can
    // be out is if it outside one of the corners
    SkPoint canonicalPt; // (x,y) translated to one of the quadrants
    int index;

    if (kOval_Type == this->type()) {
        canonicalPt.set(x - fRect.centerX(), y - fRect.centerY());
        index = kUpperLeft_Corner;  // any corner will do in this case
    } else {
        if (x < fRect.fLeft + fRadii[kUpperLeft_Corner].fX &&
            y < fRect.fTop + fRadii[kUpperLeft_Corner].fY) {
            // UL corner
            index = kUpperLeft_Corner;
            canonicalPt.set(x - (fRect.fLeft + fRadii[kUpperLeft_Corner].fX),
                            y - (fRect.fTop + fRadii[kUpperLeft_Corner].fY));
            SkASSERT(canonicalPt.fX < 0 && canonicalPt.fY < 0);
        } else if (x < fRect.fLeft + fRadii[kLowerLeft_Corner].fX &&
                   y > fRect.fBottom - fRadii[kLowerLeft_Corner].fY) {
            // LL corner
            index = kLowerLeft_Corner;
            canonicalPt.set(x - (fRect.fLeft + fRadii[kLowerLeft_Corner].fX),
                            y - (fRect.fBottom - fRadii[kLowerLeft_Corner].fY));
            SkASSERT(canonicalPt.fX < 0 && canonicalPt.fY > 0);
        } else if (x > fRect.fRight - fRadii[kUpperRight_Corner].fX &&
                   y < fRect.fTop + fRadii[kUpperRight_Corner].fY) {
            // UR corner
            index = kUpperRight_Corner;
            canonicalPt.set(x - (fRect.fRight - fRadii[kUpperRight_Corner].fX),
                            y - (fRect.fTop + fRadii[kUpperRight_Corner].fY));
            SkASSERT(canonicalPt.fX > 0 && canonicalPt.fY < 0);
        } else if (x > fRect.fRight - fRadii[kLowerRight_Corner].fX &&
                   y > fRect.fBottom - fRadii[kLowerRight_Corner].fY) {
            // LR corner
            index = kLowerRight_Corner;
            canonicalPt.set(x - (fRect.fRight - fRadii[kLowerRight_Corner].fX),
                            y - (fRect.fBottom - fRadii[kLowerRight_Corner].fY));
            SkASSERT(canonicalPt.fX > 0 && canonicalPt.fY > 0);
        } else {
            // not in any of the corners
            return true;
        }
    }

    // A point is in an ellipse (in standard position) if:
    //      x^2     y^2
    //     ----- + ----- <= 1
    //      a^2     b^2
    SkScalar dist =  SkScalarDiv(SkScalarSquare(canonicalPt.fX), SkScalarSquare(fRadii[index].fX)) +
                     SkScalarDiv(SkScalarSquare(canonicalPt.fY), SkScalarSquare(fRadii[index].fY));
    return dist <= SK_Scalar1;
}

// There is a simplified version of this method in setRectXY
void SkRRect::computeType() const {
    SkDEBUGCODE(this->validate();)

    if (fRect.isEmpty()) {
        fType = kEmpty_Type;
        return;
    }

    bool allRadiiEqual = true; // are all x radii equal and all y radii?
    bool allCornersSquare = 0 == fRadii[0].fX || 0 == fRadii[0].fY;

    for (int i = 1; i < 4; ++i) {
        if (0 != fRadii[i].fX && 0 != fRadii[i].fY) {
            // if either radius is zero the corner is square so both have to
            // be non-zero to have a rounded corner
            allCornersSquare = false;
        }
        if (fRadii[i].fX != fRadii[i-1].fX || fRadii[i].fY != fRadii[i-1].fY) {
            allRadiiEqual = false;
        }
    }

    if (allCornersSquare) {
        fType = kRect_Type;
        return;
    }

    if (allRadiiEqual) {
        if (fRadii[0].fX >= SkScalarHalf(fRect.width()) &&
            fRadii[0].fY >= SkScalarHalf(fRect.height())) {
            fType = kOval_Type;
        } else {
            fType = kSimple_Type;
        }
        return;
    }

    fType = kComplex_Type;
}

#ifdef SK_DEBUG
void SkRRect::validate() const {
    bool allRadiiZero = (0 == fRadii[0].fX && 0 == fRadii[0].fY);
    bool allCornersSquare = (0 == fRadii[0].fX || 0 == fRadii[0].fY);
    bool allRadiiSame = true;

    for (int i = 1; i < 4; ++i) {
        if (0 != fRadii[i].fX || 0 != fRadii[i].fY) {
            allRadiiZero = false;
        }

        if (fRadii[i].fX != fRadii[i-1].fX || fRadii[i].fY != fRadii[i-1].fY) {
            allRadiiSame = false;
        }

        if (0 != fRadii[i].fX && 0 != fRadii[i].fY) {
            allCornersSquare = false;
        }
    }

    switch (fType) {
        case kEmpty_Type:
            SkASSERT(fRect.isEmpty());
            SkASSERT(allRadiiZero && allRadiiSame && allCornersSquare);

            SkASSERT(0 == fRect.fLeft && 0 == fRect.fTop &&
                     0 == fRect.fRight && 0 == fRect.fBottom);
            break;
        case kRect_Type:
            SkASSERT(!fRect.isEmpty());
            SkASSERT(allRadiiZero && allRadiiSame && allCornersSquare);
            break;
        case kOval_Type:
            SkASSERT(!fRect.isEmpty());
            SkASSERT(!allRadiiZero && allRadiiSame && !allCornersSquare);

            for (int i = 0; i < 4; ++i) {
                SkASSERT(SkScalarNearlyEqual(fRadii[i].fX, SkScalarHalf(fRect.width())));
                SkASSERT(SkScalarNearlyEqual(fRadii[i].fY, SkScalarHalf(fRect.height())));
            }
            break;
        case kSimple_Type:
            SkASSERT(!fRect.isEmpty());
            SkASSERT(!allRadiiZero && allRadiiSame && !allCornersSquare);
            break;
        case kComplex_Type:
            SkASSERT(!fRect.isEmpty());
            SkASSERT(!allRadiiZero && !allRadiiSame && !allCornersSquare);
            break;
        case kUnknown_Type:
            // no limits on this
            break;
    }
}
#endif // SK_DEBUG

///////////////////////////////////////////////////////////////////////////////
<commit_msg>Fix for roll-blocking compiler error in SkRRect.cpp<commit_after>/*
 * Copyright 2012 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkRRect.h"

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

void SkRRect::setRectXY(const SkRect& rect, SkScalar xRad, SkScalar yRad) {
    if (rect.isEmpty()) {
        this->setEmpty();
        return;
    }

    if (xRad <= 0 || yRad <= 0) {
        // all corners are square in this case
        this->setRect(rect);
        return;
    }

    if (rect.width() < xRad+xRad || rect.height() < yRad+yRad) {
        SkScalar scale = SkMinScalar(SkScalarDiv(rect.width(), xRad + xRad),
                                     SkScalarDiv(rect.height(), yRad + yRad));
        SkASSERT(scale < SK_Scalar1);
        xRad = SkScalarMul(xRad, scale);
        yRad = SkScalarMul(yRad, scale);
    }

    fRect = rect;
    for (int i = 0; i < 4; ++i) {
        fRadii[i].set(xRad, yRad);
    }
    fType = kSimple_Type;
    if (xRad >= SkScalarHalf(fRect.width()) && yRad >= SkScalarHalf(fRect.height())) {
        fType = kOval_Type;
        // TODO: try asserting they are already W/2 & H/2 already
        xRad = SkScalarHalf(fRect.width());
        yRad = SkScalarHalf(fRect.height());
    }

    SkDEBUGCODE(this->validate();)
}

void SkRRect::setRectRadii(const SkRect& rect, const SkVector radii[4]) {
    if (rect.isEmpty()) {
        this->setEmpty();
        return;
    }

    fRect = rect;
    memcpy(fRadii, radii, sizeof(fRadii));

    bool allCornersSquare = true;

    // Clamp negative radii to zero
    for (int i = 0; i < 4; ++i) {
        if (fRadii[i].fX <= 0 || fRadii[i].fY <= 0) {
            // In this case we are being a little fast & loose. Since one of
            // the radii is 0 the corner is square. However, the other radii
            // could still be non-zero and play in the global scale factor
            // computation.
            fRadii[i].fX = 0;
            fRadii[i].fY = 0;
        } else {
            allCornersSquare = false;
        }
    }

    if (allCornersSquare) {
        this->setRect(rect);
        return;
    }

    // Proportionally scale down all radii to fit. Find the minimum ratio
    // of a side and the radii on that side (for all four sides) and use
    // that to scale down _all_ the radii. This algorithm is from the
    // W3 spec (http://www.w3.org/TR/css3-background/) section 5.5 - Overlapping
    // Curves:
    // "Let f = min(Li/Si), where i is one of { top, right, bottom, left },
    //   Si is the sum of the two corresponding radii of the corners on side i,
    //   and Ltop = Lbottom = the width of the box,
    //   and Lleft = Lright = the height of the box.
    // If f < 1, then all corner radii are reduced by multiplying them by f."
    SkScalar scale = SK_Scalar1;

    if (fRadii[0].fX + fRadii[1].fX > rect.width()) {
        scale = SkMinScalar(scale,
                            SkScalarDiv(rect.width(), fRadii[0].fX + fRadii[1].fX));
    }
    if (fRadii[1].fY + fRadii[2].fY > rect.height()) {
        scale = SkMinScalar(scale,
                            SkScalarDiv(rect.height(), fRadii[1].fY + fRadii[2].fY));
    }
    if (fRadii[2].fX + fRadii[3].fX > rect.width()) {
        scale = SkMinScalar(scale,
                            SkScalarDiv(rect.width(), fRadii[2].fX + fRadii[3].fX));
    }
    if (fRadii[3].fY + fRadii[0].fY > rect.height()) {
        scale = SkMinScalar(scale,
                            SkScalarDiv(rect.height(), fRadii[3].fY + fRadii[0].fY));
    }

    if (scale < SK_Scalar1) {
        for (int i = 0; i < 4; ++i) {
            fRadii[i].fX = SkScalarMul(fRadii[i].fX, scale);
            fRadii[i].fY = SkScalarMul(fRadii[i].fY, scale);
        }
    }

    // At this point we're either oval, simple, or complex (not empty or rect)
    // but we lazily resolve the type to avoid the work if the information
    // isn't required.
    fType = (SkRRect::Type) kUnknown_Type;

    SkDEBUGCODE(this->validate();)
}

bool SkRRect::contains(SkScalar x, SkScalar y) const {
    SkDEBUGCODE(this->validate();)

    if (kEmpty_Type == this->type()) {
        return false;
    }

    if (!fRect.contains(x, y)) {
        return false;
    }

    if (kRect_Type == this->type()) {
        // the 'fRect' test above was sufficient
        return true;
    }

    // We know the point is inside the RR's bounds. The only way it can
    // be out is if it outside one of the corners
    SkPoint canonicalPt; // (x,y) translated to one of the quadrants
    int index;

    if (kOval_Type == this->type()) {
        canonicalPt.set(x - fRect.centerX(), y - fRect.centerY());
        index = kUpperLeft_Corner;  // any corner will do in this case
    } else {
        if (x < fRect.fLeft + fRadii[kUpperLeft_Corner].fX &&
            y < fRect.fTop + fRadii[kUpperLeft_Corner].fY) {
            // UL corner
            index = kUpperLeft_Corner;
            canonicalPt.set(x - (fRect.fLeft + fRadii[kUpperLeft_Corner].fX),
                            y - (fRect.fTop + fRadii[kUpperLeft_Corner].fY));
            SkASSERT(canonicalPt.fX < 0 && canonicalPt.fY < 0);
        } else if (x < fRect.fLeft + fRadii[kLowerLeft_Corner].fX &&
                   y > fRect.fBottom - fRadii[kLowerLeft_Corner].fY) {
            // LL corner
            index = kLowerLeft_Corner;
            canonicalPt.set(x - (fRect.fLeft + fRadii[kLowerLeft_Corner].fX),
                            y - (fRect.fBottom - fRadii[kLowerLeft_Corner].fY));
            SkASSERT(canonicalPt.fX < 0 && canonicalPt.fY > 0);
        } else if (x > fRect.fRight - fRadii[kUpperRight_Corner].fX &&
                   y < fRect.fTop + fRadii[kUpperRight_Corner].fY) {
            // UR corner
            index = kUpperRight_Corner;
            canonicalPt.set(x - (fRect.fRight - fRadii[kUpperRight_Corner].fX),
                            y - (fRect.fTop + fRadii[kUpperRight_Corner].fY));
            SkASSERT(canonicalPt.fX > 0 && canonicalPt.fY < 0);
        } else if (x > fRect.fRight - fRadii[kLowerRight_Corner].fX &&
                   y > fRect.fBottom - fRadii[kLowerRight_Corner].fY) {
            // LR corner
            index = kLowerRight_Corner;
            canonicalPt.set(x - (fRect.fRight - fRadii[kLowerRight_Corner].fX),
                            y - (fRect.fBottom - fRadii[kLowerRight_Corner].fY));
            SkASSERT(canonicalPt.fX > 0 && canonicalPt.fY > 0);
        } else {
            // not in any of the corners
            return true;
        }
    }

    // A point is in an ellipse (in standard position) if:
    //      x^2     y^2
    //     ----- + ----- <= 1
    //      a^2     b^2
    SkScalar dist =  SkScalarDiv(SkScalarSquare(canonicalPt.fX), SkScalarSquare(fRadii[index].fX)) +
                     SkScalarDiv(SkScalarSquare(canonicalPt.fY), SkScalarSquare(fRadii[index].fY));
    return dist <= SK_Scalar1;
}

// There is a simplified version of this method in setRectXY
void SkRRect::computeType() const {
    SkDEBUGCODE(this->validate();)

    if (fRect.isEmpty()) {
        fType = kEmpty_Type;
        return;
    }

    bool allRadiiEqual = true; // are all x radii equal and all y radii?
    bool allCornersSquare = 0 == fRadii[0].fX || 0 == fRadii[0].fY;

    for (int i = 1; i < 4; ++i) {
        if (0 != fRadii[i].fX && 0 != fRadii[i].fY) {
            // if either radius is zero the corner is square so both have to
            // be non-zero to have a rounded corner
            allCornersSquare = false;
        }
        if (fRadii[i].fX != fRadii[i-1].fX || fRadii[i].fY != fRadii[i-1].fY) {
            allRadiiEqual = false;
        }
    }

    if (allCornersSquare) {
        fType = kRect_Type;
        return;
    }

    if (allRadiiEqual) {
        if (fRadii[0].fX >= SkScalarHalf(fRect.width()) &&
            fRadii[0].fY >= SkScalarHalf(fRect.height())) {
            fType = kOval_Type;
        } else {
            fType = kSimple_Type;
        }
        return;
    }

    fType = kComplex_Type;
}

#ifdef SK_DEBUG
void SkRRect::validate() const {
    bool allRadiiZero = (0 == fRadii[0].fX && 0 == fRadii[0].fY);
    bool allCornersSquare = (0 == fRadii[0].fX || 0 == fRadii[0].fY);
    bool allRadiiSame = true;

    for (int i = 1; i < 4; ++i) {
        if (0 != fRadii[i].fX || 0 != fRadii[i].fY) {
            allRadiiZero = false;
        }

        if (fRadii[i].fX != fRadii[i-1].fX || fRadii[i].fY != fRadii[i-1].fY) {
            allRadiiSame = false;
        }

        if (0 != fRadii[i].fX && 0 != fRadii[i].fY) {
            allCornersSquare = false;
        }
    }

    switch (fType) {
        case kEmpty_Type:
            SkASSERT(fRect.isEmpty());
            SkASSERT(allRadiiZero && allRadiiSame && allCornersSquare);

            SkASSERT(0 == fRect.fLeft && 0 == fRect.fTop &&
                     0 == fRect.fRight && 0 == fRect.fBottom);
            break;
        case kRect_Type:
            SkASSERT(!fRect.isEmpty());
            SkASSERT(allRadiiZero && allRadiiSame && allCornersSquare);
            break;
        case kOval_Type:
            SkASSERT(!fRect.isEmpty());
            SkASSERT(!allRadiiZero && allRadiiSame && !allCornersSquare);

            for (int i = 0; i < 4; ++i) {
                SkASSERT(SkScalarNearlyEqual(fRadii[i].fX, SkScalarHalf(fRect.width())));
                SkASSERT(SkScalarNearlyEqual(fRadii[i].fY, SkScalarHalf(fRect.height())));
            }
            break;
        case kSimple_Type:
            SkASSERT(!fRect.isEmpty());
            SkASSERT(!allRadiiZero && allRadiiSame && !allCornersSquare);
            break;
        case kComplex_Type:
            SkASSERT(!fRect.isEmpty());
            SkASSERT(!allRadiiZero && !allRadiiSame && !allCornersSquare);
            break;
#if 0
        // error: case value not in enumerated type 'SkRRect::Type
        case kUnknown_Type:
            // no limits on this
            break;
#endif
    }
}
#endif // SK_DEBUG

///////////////////////////////////////////////////////////////////////////////
<|endoftext|>


<commit_before>#include "CssTokenizer.h"

CssTokenizer::CssTokenizer(istream* in){
  this->in = in;
  line = 1;
  column = 0;
  readChar();
}

CssTokenizer::~CssTokenizer(){
}

void CssTokenizer::readChar(){
  if (in == NULL)
    return;

  // Last char was a newline. Increment the line counter.
  if (lastReadEq('\n')) {
    line++;
    column = 0;
  }

  in->get(lastRead);

  // check for end of file or escape key
  if(in->eof() || lastRead == 27)
    in = NULL;
  else if (in->fail() || in->bad())
    throw new IOException("Error reading input");

  if (!lastReadEq('\n')) // count chars that aren't newlines
    column++;
}

Token::Type CssTokenizer::readNextToken(){
  if (in == NULL) {
    currentToken.type = Token::EOS;
    return Token::EOS;
  }

  currentToken.clear();
  switch (lastRead) {
  case '@':
    currentToken.type = Token::ATKEYWORD;
    currentToken.add(lastRead);
    readChar();
    if (!readIdent()) {
      currentToken.type = Token::OTHER;
    }
    break;

  case '#':
    currentToken.type = Token::HASH;
    currentToken.add(lastRead);
    readChar();
    if (!readName()) {
      throw new ParseException(&lastRead,
                               "name following '#'");
    }
    break;

  case '-':
    currentToken.add(lastRead);
    readChar();
    if (readNum()) {
      currentToken.type = Token::NUMBER;
      if (lastReadEq('%')) {
        currentToken.type = Token::PERCENTAGE;
        currentToken.add(lastRead);
        readChar();
      } else if (readIdent())
        currentToken.type = Token::DIMENSION;
    } else if (readIdent()) {
      currentToken.type = Token::IDENTIFIER;
      if (lastRead == '(') {
        currentToken.add(lastRead);
        readChar();
        currentToken.type = Token::FUNCTION;
      }
    } else
      currentToken.type = Token::OTHER;
    break;

  case '~':
    currentToken.add(lastRead);
    readChar();
    if (lastRead == '=') {
      currentToken.add(lastRead);
      readChar();
      currentToken.type = Token::INCLUDES;
    } else
      currentToken.type = Token::OTHER;
    break;

  case '|':
    currentToken.add(lastRead);
    readChar();
    if (lastRead == '=') {
      currentToken.add(lastRead);
      readChar();
      currentToken.type = Token::DASHMATCH;
    } else
      currentToken.type = Token::OTHER;
    break;

  case '/':
    currentToken.add(lastRead);
    readChar();
    if (readComment())
      currentToken.type = Token::COMMENT;
    else
      currentToken.type = Token::OTHER;
    break;

  case ';':
    currentToken.type = Token::DELIMITER;
    currentToken.add(lastRead);
    readChar();
    break;
  case ':':
    currentToken.type = Token::COLON;
    currentToken.add(lastRead);
    readChar();
    break;
  case '{':
    currentToken.type = Token::BRACKET_OPEN;
    currentToken.add(lastRead);
    readChar();
    break;
  case '}':
    currentToken.type = Token::BRACKET_CLOSED;
    currentToken.add(lastRead);
    readChar();
    break;
  case '(':
    currentToken.type = Token::PAREN_OPEN;
    currentToken.add(lastRead);
    readChar();
    break;
  case ')':
    currentToken.type = Token::PAREN_CLOSED;
    currentToken.add(lastRead);
    readChar();
    break;
  case '[':
    currentToken.type = Token::BRACE_OPEN;
    currentToken.add(lastRead);
    readChar();
    break;
  case ']':
    currentToken.type = Token::BRACE_CLOSED;
    currentToken.add(lastRead);
    readChar();
    break;

  default:
    if (readString())
      currentToken.type = Token::STRING;
    else if (readNum()) {
      currentToken.type = Token::NUMBER;
      if (lastRead == '%') {
        currentToken.type = Token::PERCENTAGE;
        currentToken.add(lastRead);
        readChar();
      } else if (readIdent())
        currentToken.type = Token::DIMENSION;

    } else if (readIdent()) {
      currentToken.type = Token::IDENTIFIER;

      if (currentToken.str == "url" && readUrl())
        currentToken.type = Token::URL;
      else if (currentToken.str == "u" && lastReadEq('+')) {
        currentToken.add(lastRead);
        readChar();
        currentToken.type = Token::UNICODE_RANGE;
        readUnicodeRange();
      } else if (lastReadEq('(')) {
        currentToken.add(lastRead);
        readChar();
        currentToken.type = Token::FUNCTION;
      }
    } else if (readWhitespace()) {
      currentToken.type = Token::WHITESPACE;
      while (readWhitespace()) {};
    }
    break;
  }

  return currentToken.type;
}

bool CssTokenizer::readIdent () {
  if (lastReadEq('-')) {
    currentToken.add(lastRead);
    readChar();
  }
  if (!readNMStart())
    return false;
  else
    while (readNMChar()) {}
  return true;
}

bool CssTokenizer::readName () {
  if (!readNMChar())
    return false;
  while (readNMChar()) {}
  return true;
}

bool CssTokenizer::readNMStart () {
  if (in == NULL)
    return false;

  if (lastReadEq('_') ||
      lastReadInRange('a', 'z') ||
      lastReadInRange('A', 'Z')) {
    currentToken.add(lastRead);
    readChar();
    return true;
  } else
    return (readNonAscii() || readEscape());
}
bool CssTokenizer::readNonAscii () {
  if (in == NULL)
    return false;

  if (lastRead >= 0) {
    return false;
  } else {
    currentToken.add(lastRead);
    readChar();
    return true;
  }
}
bool CssTokenizer::readEscape () {
  if (!lastReadEq('\\'))
    return false;
  currentToken.add(lastRead);
  readChar();

  if (readUnicode())
    return true;
  else if (!lastReadEq('\n') &&
           !lastReadEq('\r') &&
           !lastReadEq('\f')) {
    currentToken.add(lastRead);
    readChar();
    return true;
  } else
    return false;
}
bool CssTokenizer::readUnicode () {
  if (!lastReadIsHex())
    return false;

  // [0-9a-f]{1,6}(\r\n|[ \n\r\t\f])?
  for (int i=0; i < 6; i++) {
    currentToken.add(lastRead);
    readChar();
    if (readWhitespace() || !lastReadIsHex())
      break;
  }
  return true;
}

bool CssTokenizer::readNMChar () {
  if (in == NULL)
    return false;

  if (lastReadEq('_') ||
      lastReadInRange('a', 'z') ||
      lastReadInRange('A', 'Z') ||
      lastReadIsDigit() ||
      lastReadEq('-')) {
    currentToken.add(lastRead);
    readChar();
    return true;
  } else
    return (readNonAscii() || readEscape());
}

bool CssTokenizer::readNum () {
  if (!lastReadIsDigit() && !lastReadEq('.'))
    return false;
  while (lastReadIsDigit()) {
    currentToken.add(lastRead);
    readChar();
  }
  if (lastReadEq('.')) {
    currentToken.add(lastRead);
    readChar();

    while (lastReadIsDigit()) {
      currentToken.add(lastRead);
      readChar();
    }
  }
  return true;
}

bool CssTokenizer::readString() {
  if (!lastReadEq('"') && !lastReadEq('\''))
    return false;
  char delim = lastRead;

  currentToken.add(lastRead);
  readChar();
  while (in != NULL) {
    if (lastReadEq(delim)) {
      currentToken.add(lastRead);
      readChar();
      return true;
    } else if (lastReadEq('\n') ||
               lastReadEq('\r') ||
               lastReadEq('\f')) {
      throw new ParseException("end of line",
                               "end of string");
    } else if (lastReadEq('\\'))
      // note that even though readEscape() returns false it still
      // eats the '\'.
      readEscape() || readNewline();
    else {
      currentToken.add(lastRead);
      readChar();
    }
  }
  throw new ParseException("end of input",
                           "end of string");
  return false;
}

bool CssTokenizer::readNewline () {
  if (lastReadEq('\r')) {
    currentToken.add(lastRead);
    readChar();
    if (lastReadEq('\n')) {
      currentToken.add(lastRead);
      readChar();
    }
    return true;
  } else if (lastReadEq('\n') ||
             lastReadEq('\f')) {
    currentToken.add(lastRead);
    readChar();
    return true;
  } else
    return false;
}

bool CssTokenizer::readWhitespace () {
  if (lastReadEq(' ') ||
      lastReadEq('\t') ||
      lastReadEq('\r') ||
      lastReadEq('\n') ||
      lastReadEq('\f')) {
    currentToken.add(lastRead);
    readChar();
    return true;
  } else
    return false;
}

bool CssTokenizer::readUrl() {
  string urlchars = "!#$%&*-[]-~";

  if (!lastReadEq('('))
    return false;
  currentToken.add(lastRead);
  readChar();
  while(readWhitespace()) {};

  if (readString()) {
    if (lastReadEq(')')) {
      currentToken.add(lastRead);
      readChar();
      return true;
    } else {
      throw new ParseException(&lastRead,
                               "end of url (')')");
    }
  }

  while (in != NULL) {
    if (readWhitespace() || lastReadEq(')')) {
      while (readWhitespace()) {};
      if (lastReadEq(')')) {
        currentToken.add(lastRead);
        readChar();
        return true;
      } else {
        throw new ParseException(&lastRead,
                                 "end of url (')')");
      }
    } else if (in != NULL && urlchars.find(lastRead)) {
      currentToken.add(lastRead);
      readChar();
    } else if (!readNonAscii() &&
               !readEscape()) {
      throw new ParseException(&lastRead,
                               "end of url (')')");
    }
  }
  throw new ParseException(&lastRead,
                           "end of url (')')");
  return false;
}

bool CssTokenizer::readComment () {
  if (!lastReadEq('*'))
    return false;
  currentToken.add(lastRead);
  readChar();
  while (in != NULL) {
    if (lastReadEq('*')) {
      currentToken.add(lastRead);
      readChar();

      if (lastReadEq('/')) {
        currentToken.add(lastRead);
        readChar();
        return true;
      }
    }
    currentToken.add(lastRead);
    readChar();
  }
  throw new ParseException(&lastRead,
                           "end of comment (*/)");
  return false;
}

bool CssTokenizer::readUnicodeRange () {
  if (in == NULL)
    return false;
  for (int i=0; i < 6; i++) {
    if (!lastReadIsHex())
      break;
    currentToken.add(lastRead);
    readChar();
  }
  if (!lastReadEq('-'))
    return true;

  for (int i=0; i < 6; i++) {
    if (!lastReadIsHex())
      break;
    currentToken.add(lastRead);
    readChar();
  }
  return true;
}

Token* CssTokenizer::getToken(){
  return &currentToken;
}
Token::Type CssTokenizer::getTokenType() {
  return currentToken.type;
}

unsigned int CssTokenizer::getLineNumber(){
  return line;
}
unsigned int CssTokenizer::getColumn(){
  return column;
}

bool CssTokenizer::lastReadEq(char c) {
  return (in != NULL && lastRead == c);
}

bool CssTokenizer::lastReadInRange(char c1, char c2) {
  return (in != NULL && lastRead >= c1 && lastRead <= c2);
}
bool CssTokenizer::lastReadIsDigit() {
  return (in != NULL &&
          lastReadInRange('0', '9'));
}
bool CssTokenizer::lastReadIsHex() {
  return (in != NULL &&
          (lastReadIsDigit() ||
           lastReadInRange('a', 'f') ||
           lastReadInRange('A', 'F')));
}
<commit_msg>Fixed bug in CssTokenizer so it reads characters of Token::OTHER type tokens.<commit_after>#include "CssTokenizer.h"

CssTokenizer::CssTokenizer(istream* in){
  this->in = in;
  line = 1;
  column = 0;
  readChar();
}

CssTokenizer::~CssTokenizer(){
}

void CssTokenizer::readChar(){
  if (in == NULL)
    return;

  // Last char was a newline. Increment the line counter.
  if (lastReadEq('\n')) {
    line++;
    column = 0;
  }

  in->get(lastRead);

  // check for end of file or escape key
  if(in->eof() || lastRead == 27)
    in = NULL;
  else if (in->fail() || in->bad())
    throw new IOException("Error reading input");

  if (!lastReadEq('\n')) // count chars that aren't newlines
    column++;
}

Token::Type CssTokenizer::readNextToken(){
  if (in == NULL) {
    currentToken.type = Token::EOS;
    return Token::EOS;
  }

  currentToken.clear();
  switch (lastRead) {
  case '@':
    currentToken.type = Token::ATKEYWORD;
    currentToken.add(lastRead);
    readChar();
    if (!readIdent()) {
      currentToken.type = Token::OTHER;
    }
    break;

  case '#':
    currentToken.type = Token::HASH;
    currentToken.add(lastRead);
    readChar();
    if (!readName()) {
      throw new ParseException(&lastRead,
                               "name following '#'");
    }
    break;

  case '-':
    currentToken.add(lastRead);
    readChar();
    if (readNum()) {
      currentToken.type = Token::NUMBER;
      if (lastReadEq('%')) {
        currentToken.type = Token::PERCENTAGE;
        currentToken.add(lastRead);
        readChar();
      } else if (readIdent())
        currentToken.type = Token::DIMENSION;
    } else if (readIdent()) {
      currentToken.type = Token::IDENTIFIER;
      if (lastRead == '(') {
        currentToken.add(lastRead);
        readChar();
        currentToken.type = Token::FUNCTION;
      }
    } else
      currentToken.type = Token::OTHER;
    break;

  case '~':
    currentToken.add(lastRead);
    readChar();
    if (lastRead == '=') {
      currentToken.add(lastRead);
      readChar();
      currentToken.type = Token::INCLUDES;
    } else
      currentToken.type = Token::OTHER;
    break;

  case '|':
    currentToken.add(lastRead);
    readChar();
    if (lastRead == '=') {
      currentToken.add(lastRead);
      readChar();
      currentToken.type = Token::DASHMATCH;
    } else
      currentToken.type = Token::OTHER;
    break;

  case '/':
    currentToken.add(lastRead);
    readChar();
    if (readComment())
      currentToken.type = Token::COMMENT;
    else
      currentToken.type = Token::OTHER;
    break;

  case ';':
    currentToken.type = Token::DELIMITER;
    currentToken.add(lastRead);
    readChar();
    break;
  case ':':
    currentToken.type = Token::COLON;
    currentToken.add(lastRead);
    readChar();
    break;
  case '{':
    currentToken.type = Token::BRACKET_OPEN;
    currentToken.add(lastRead);
    readChar();
    break;
  case '}':
    currentToken.type = Token::BRACKET_CLOSED;
    currentToken.add(lastRead);
    readChar();
    break;
  case '(':
    currentToken.type = Token::PAREN_OPEN;
    currentToken.add(lastRead);
    readChar();
    break;
  case ')':
    currentToken.type = Token::PAREN_CLOSED;
    currentToken.add(lastRead);
    readChar();
    break;
  case '[':
    currentToken.type = Token::BRACE_OPEN;
    currentToken.add(lastRead);
    readChar();
    break;
  case ']':
    currentToken.type = Token::BRACE_CLOSED;
    currentToken.add(lastRead);
    readChar();
    break;

  default:
    if (readString())
      currentToken.type = Token::STRING;
    else if (readNum()) {
      currentToken.type = Token::NUMBER;
      if (lastRead == '%') {
        currentToken.type = Token::PERCENTAGE;
        currentToken.add(lastRead);
        readChar();
      } else if (readIdent())
        currentToken.type = Token::DIMENSION;

    } else if (readIdent()) {
      currentToken.type = Token::IDENTIFIER;

      if (currentToken.str == "url" && readUrl())
        currentToken.type = Token::URL;
      else if (currentToken.str == "u" && lastReadEq('+')) {
        currentToken.add(lastRead);
        readChar();
        currentToken.type = Token::UNICODE_RANGE;
        readUnicodeRange();
      } else if (lastReadEq('(')) {
        currentToken.add(lastRead);
        readChar();
        currentToken.type = Token::FUNCTION;
      }
    } else if (readWhitespace()) {
      currentToken.type = Token::WHITESPACE;
      while (readWhitespace()) {};
    } else {
      currentToken.add(lastRead);
      readChar();
    }
    break;
  }

  return currentToken.type;
}

bool CssTokenizer::readIdent () {
  if (lastReadEq('-')) {
    currentToken.add(lastRead);
    readChar();
  }
  if (!readNMStart())
    return false;
  else
    while (readNMChar()) {}
  return true;
}

bool CssTokenizer::readName () {
  if (!readNMChar())
    return false;
  while (readNMChar()) {}
  return true;
}

bool CssTokenizer::readNMStart () {
  if (in == NULL)
    return false;

  if (lastReadEq('_') ||
      lastReadInRange('a', 'z') ||
      lastReadInRange('A', 'Z')) {
    currentToken.add(lastRead);
    readChar();
    return true;
  } else
    return (readNonAscii() || readEscape());
}
bool CssTokenizer::readNonAscii () {
  if (in == NULL)
    return false;

  if (lastRead >= 0) {
    return false;
  } else {
    currentToken.add(lastRead);
    readChar();
    return true;
  }
}
bool CssTokenizer::readEscape () {
  if (!lastReadEq('\\'))
    return false;
  currentToken.add(lastRead);
  readChar();

  if (readUnicode())
    return true;
  else if (!lastReadEq('\n') &&
           !lastReadEq('\r') &&
           !lastReadEq('\f')) {
    currentToken.add(lastRead);
    readChar();
    return true;
  } else
    return false;
}
bool CssTokenizer::readUnicode () {
  if (!lastReadIsHex())
    return false;

  // [0-9a-f]{1,6}(\r\n|[ \n\r\t\f])?
  for (int i=0; i < 6; i++) {
    currentToken.add(lastRead);
    readChar();
    if (readWhitespace() || !lastReadIsHex())
      break;
  }
  return true;
}

bool CssTokenizer::readNMChar () {
  if (in == NULL)
    return false;

  if (lastReadEq('_') ||
      lastReadInRange('a', 'z') ||
      lastReadInRange('A', 'Z') ||
      lastReadIsDigit() ||
      lastReadEq('-')) {
    currentToken.add(lastRead);
    readChar();
    return true;
  } else
    return (readNonAscii() || readEscape());
}

bool CssTokenizer::readNum () {
  if (!lastReadIsDigit() && !lastReadEq('.'))
    return false;
  while (lastReadIsDigit()) {
    currentToken.add(lastRead);
    readChar();
  }
  if (lastReadEq('.')) {
    currentToken.add(lastRead);
    readChar();

    while (lastReadIsDigit()) {
      currentToken.add(lastRead);
      readChar();
    }
  }
  return true;
}

bool CssTokenizer::readString() {
  if (!lastReadEq('"') && !lastReadEq('\''))
    return false;
  char delim = lastRead;

  currentToken.add(lastRead);
  readChar();
  while (in != NULL) {
    if (lastReadEq(delim)) {
      currentToken.add(lastRead);
      readChar();
      return true;
    } else if (lastReadEq('\n') ||
               lastReadEq('\r') ||
               lastReadEq('\f')) {
      throw new ParseException("end of line",
                               "end of string");
    } else if (lastReadEq('\\'))
      // note that even though readEscape() returns false it still
      // eats the '\'.
      readEscape() || readNewline();
    else {
      currentToken.add(lastRead);
      readChar();
    }
  }
  throw new ParseException("end of input",
                           "end of string");
  return false;
}

bool CssTokenizer::readNewline () {
  if (lastReadEq('\r')) {
    currentToken.add(lastRead);
    readChar();
    if (lastReadEq('\n')) {
      currentToken.add(lastRead);
      readChar();
    }
    return true;
  } else if (lastReadEq('\n') ||
             lastReadEq('\f')) {
    currentToken.add(lastRead);
    readChar();
    return true;
  } else
    return false;
}

bool CssTokenizer::readWhitespace () {
  if (lastReadEq(' ') ||
      lastReadEq('\t') ||
      lastReadEq('\r') ||
      lastReadEq('\n') ||
      lastReadEq('\f')) {
    currentToken.add(lastRead);
    readChar();
    return true;
  } else
    return false;
}

bool CssTokenizer::readUrl() {
  string urlchars = "!#$%&*-[]-~";

  if (!lastReadEq('('))
    return false;
  currentToken.add(lastRead);
  readChar();
  while(readWhitespace()) {};

  if (readString()) {
    if (lastReadEq(')')) {
      currentToken.add(lastRead);
      readChar();
      return true;
    } else {
      throw new ParseException(&lastRead,
                               "end of url (')')");
    }
  }

  while (in != NULL) {
    if (readWhitespace() || lastReadEq(')')) {
      while (readWhitespace()) {};
      if (lastReadEq(')')) {
        currentToken.add(lastRead);
        readChar();
        return true;
      } else {
        throw new ParseException(&lastRead,
                                 "end of url (')')");
      }
    } else if (in != NULL && urlchars.find(lastRead)) {
      currentToken.add(lastRead);
      readChar();
    } else if (!readNonAscii() &&
               !readEscape()) {
      throw new ParseException(&lastRead,
                               "end of url (')')");
    }
  }
  throw new ParseException(&lastRead,
                           "end of url (')')");
  return false;
}

bool CssTokenizer::readComment () {
  if (!lastReadEq('*'))
    return false;
  currentToken.add(lastRead);
  readChar();
  while (in != NULL) {
    if (lastReadEq('*')) {
      currentToken.add(lastRead);
      readChar();

      if (lastReadEq('/')) {
        currentToken.add(lastRead);
        readChar();
        return true;
      }
    }
    currentToken.add(lastRead);
    readChar();
  }
  throw new ParseException(&lastRead,
                           "end of comment (*/)");
  return false;
}

bool CssTokenizer::readUnicodeRange () {
  if (in == NULL)
    return false;
  for (int i=0; i < 6; i++) {
    if (!lastReadIsHex())
      break;
    currentToken.add(lastRead);
    readChar();
  }
  if (!lastReadEq('-'))
    return true;

  for (int i=0; i < 6; i++) {
    if (!lastReadIsHex())
      break;
    currentToken.add(lastRead);
    readChar();
  }
  return true;
}

Token* CssTokenizer::getToken(){
  return &currentToken;
}
Token::Type CssTokenizer::getTokenType() {
  return currentToken.type;
}

unsigned int CssTokenizer::getLineNumber(){
  return line;
}
unsigned int CssTokenizer::getColumn(){
  return column;
}

bool CssTokenizer::lastReadEq(char c) {
  return (in != NULL && lastRead == c);
}

bool CssTokenizer::lastReadInRange(char c1, char c2) {
  return (in != NULL && lastRead >= c1 && lastRead <= c2);
}
bool CssTokenizer::lastReadIsDigit() {
  return (in != NULL &&
          lastReadInRange('0', '9'));
}
bool CssTokenizer::lastReadIsHex() {
  return (in != NULL &&
          (lastReadIsDigit() ||
           lastReadInRange('a', 'f') ||
           lastReadInRange('A', 'F')));
}
<|endoftext|>


<commit_before>/****************************************************************************
** libebml : parse EBML files, see http://embl.sourceforge.net/
**
** <file/class description>
**
** Copyright (C) 2002-2010 Steve Lhomme.  All rights reserved.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License as published by the Free Software Foundation; either
** version 2.1 of the License, or (at your option) any later version.
**
** This library 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 for more details.
**
** You should have received a copy of the GNU Lesser General Public
** License along with this library; if not, write to the Free Software
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
**
** See http://www.gnu.org/licenses/lgpl-2.1.html for LGPL licensing information.
**
** Contact license@matroska.org if any conditions of this licensing are
** not clear to you.
**
**********************************************************************/

/*!
  \file
  \version \$Id$
  \author Steve Lhomme     <robux4 @ users.sf.net>
  \author Moritz Bunkus <moritz @ bunkus.org>
*/
#include <cassert>

#include "ebml/EbmlSInteger.h"

START_LIBEBML_NAMESPACE

EbmlSInteger::EbmlSInteger()
  :EbmlElement(DEFAULT_INT_SIZE, false)
{}

EbmlSInteger::EbmlSInteger(int64 aDefaultValue)
  :EbmlElement(DEFAULT_INT_SIZE, true), Value(aDefaultValue)
{
  SetDefaultIsSet();
}

EbmlSInteger::EbmlSInteger(const EbmlSInteger & ElementToClone)
  :EbmlElement(ElementToClone)
  ,Value(ElementToClone.Value)
  ,DefaultValue(ElementToClone.DefaultValue)
{
}

EbmlSInteger::operator int8() const {return  int8(Value);}
EbmlSInteger::operator int16() const {return int16(Value);}
EbmlSInteger::operator int32() const {return int32(Value);}
EbmlSInteger::operator int64() const {return Value;}

int64 EbmlSInteger::GetValue() const {return Value;}

EbmlSInteger & EbmlSInteger::SetValue(int64 NewValue) {
  return *this = NewValue;
}

/*!
  \todo handle exception on errors
*/
filepos_t EbmlSInteger::RenderData(IOCallback & output, bool /* bForceRender */, bool /* bWithDefault */)
{
  binary FinalData[8]; // we don't handle more than 64 bits integers
  unsigned int i;

  if (GetSizeLength() > 8)
    return 0; // integer bigger coded on more than 64 bits are not supported

  int64 TempValue = Value;
  for (i=0; i<GetSize();i++) {
    FinalData[GetSize()-i-1] = binary(TempValue & 0xFF);
    TempValue >>= 8;
  }

  output.writeFully(FinalData,GetSize());

  return GetSize();
}

uint64 EbmlSInteger::UpdateSize(bool bWithDefault, bool /* bForceRender */)
{
  if (!bWithDefault && IsDefaultValue())
    return 0;

  if (Value <= 0x7F && Value >= (-0x80)) {
    SetSize_(1);
  } else if (Value <= 0x7FFF && Value >= (-0x8000)) {
    SetSize_(2);
  } else if (Value <= 0x7FFFFF && Value >= (-0x800000)) {
    SetSize_(3);
  } else if (Value <= EBML_PRETTYLONGINT(0x7FFFFFFF) && Value >= (EBML_PRETTYLONGINT(-0x80000000))) {
    SetSize_(4);
  } else if (Value <= EBML_PRETTYLONGINT(0x7FFFFFFFFF) &&
             Value >= EBML_PRETTYLONGINT(-0x8000000000)) {
    SetSize_(5);
  } else if (Value <= EBML_PRETTYLONGINT(0x7FFFFFFFFFFF) &&
             Value >= EBML_PRETTYLONGINT(-0x800000000000)) {
    SetSize_(6);
  } else if (Value <= EBML_PRETTYLONGINT(0x7FFFFFFFFFFFFF) &&
             Value >= EBML_PRETTYLONGINT(-0x80000000000000)) {
    SetSize_(7);
  } else {
    SetSize_(8);
  }

  if (GetDefaultSize() > GetSize()) {
    SetSize_(GetDefaultSize());
  }

  return GetSize();
}

filepos_t EbmlSInteger::ReadData(IOCallback & input, ScopeMode ReadFully)
{
  if (ReadFully != SCOPE_NO_DATA) {
    binary Buffer[8];
    input.readFully(Buffer, GetSize());

    if (Buffer[0] & 0x80)
      Value = -1; // this is a negative value
    else
      Value = 0; // this is a positive value

    for (unsigned int i=0; i<GetSize(); i++) {
      Value <<= 8;
      Value |= Buffer[i];
    }
    SetValueIsSet();
  }

  return GetSize();
}

bool EbmlSInteger::IsSmallerThan(const EbmlElement *Cmp) const
{
  if (EbmlId(*this) == EbmlId(*Cmp))
    return this->Value < static_cast<const EbmlSInteger *>(Cmp)->Value;
  else
    return false;
}

END_LIBEBML_NAMESPACE
<commit_msg>EbmlSInteger: avoid undefined behavior when reading<commit_after>/****************************************************************************
** libebml : parse EBML files, see http://embl.sourceforge.net/
**
** <file/class description>
**
** Copyright (C) 2002-2010 Steve Lhomme.  All rights reserved.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License as published by the Free Software Foundation; either
** version 2.1 of the License, or (at your option) any later version.
**
** This library 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 for more details.
**
** You should have received a copy of the GNU Lesser General Public
** License along with this library; if not, write to the Free Software
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
**
** See http://www.gnu.org/licenses/lgpl-2.1.html for LGPL licensing information.
**
** Contact license@matroska.org if any conditions of this licensing are
** not clear to you.
**
**********************************************************************/

/*!
  \file
  \version \$Id$
  \author Steve Lhomme     <robux4 @ users.sf.net>
  \author Moritz Bunkus <moritz @ bunkus.org>
*/
#include <cassert>
#include <climits>

#include "ebml/EbmlSInteger.h"

// Converting unsigned int types to signed ints assuming the
// underlying bits in memory should represent the 2's complement of a
// signed integer. See https://stackoverflow.com/a/13208789/507077

namespace {

int64_t
ToSigned(uint64_t u) {
  if (u <= std::numeric_limits<int64_t>::max())
    return static_cast<int64_t>(u);

  return static_cast<int64_t>(u - std::numeric_limits<int64_t>::min()) + std::numeric_limits<int64_t>::min();
}

}

START_LIBEBML_NAMESPACE

EbmlSInteger::EbmlSInteger()
  :EbmlElement(DEFAULT_INT_SIZE, false)
{}

EbmlSInteger::EbmlSInteger(int64 aDefaultValue)
  :EbmlElement(DEFAULT_INT_SIZE, true), Value(aDefaultValue)
{
  SetDefaultIsSet();
}

EbmlSInteger::EbmlSInteger(const EbmlSInteger & ElementToClone)
  :EbmlElement(ElementToClone)
  ,Value(ElementToClone.Value)
  ,DefaultValue(ElementToClone.DefaultValue)
{
}

EbmlSInteger::operator int8() const {return  int8(Value);}
EbmlSInteger::operator int16() const {return int16(Value);}
EbmlSInteger::operator int32() const {return int32(Value);}
EbmlSInteger::operator int64() const {return Value;}

int64 EbmlSInteger::GetValue() const {return Value;}

EbmlSInteger & EbmlSInteger::SetValue(int64 NewValue) {
  return *this = NewValue;
}

/*!
  \todo handle exception on errors
*/
filepos_t EbmlSInteger::RenderData(IOCallback & output, bool /* bForceRender */, bool /* bWithDefault */)
{
  binary FinalData[8]; // we don't handle more than 64 bits integers
  unsigned int i;

  if (GetSizeLength() > 8)
    return 0; // integer bigger coded on more than 64 bits are not supported

  int64 TempValue = Value;
  for (i=0; i<GetSize();i++) {
    FinalData[GetSize()-i-1] = binary(TempValue & 0xFF);
    TempValue >>= 8;
  }

  output.writeFully(FinalData,GetSize());

  return GetSize();
}

uint64 EbmlSInteger::UpdateSize(bool bWithDefault, bool /* bForceRender */)
{
  if (!bWithDefault && IsDefaultValue())
    return 0;

  if (Value <= 0x7F && Value >= (-0x80)) {
    SetSize_(1);
  } else if (Value <= 0x7FFF && Value >= (-0x8000)) {
    SetSize_(2);
  } else if (Value <= 0x7FFFFF && Value >= (-0x800000)) {
    SetSize_(3);
  } else if (Value <= EBML_PRETTYLONGINT(0x7FFFFFFF) && Value >= (EBML_PRETTYLONGINT(-0x80000000))) {
    SetSize_(4);
  } else if (Value <= EBML_PRETTYLONGINT(0x7FFFFFFFFF) &&
             Value >= EBML_PRETTYLONGINT(-0x8000000000)) {
    SetSize_(5);
  } else if (Value <= EBML_PRETTYLONGINT(0x7FFFFFFFFFFF) &&
             Value >= EBML_PRETTYLONGINT(-0x800000000000)) {
    SetSize_(6);
  } else if (Value <= EBML_PRETTYLONGINT(0x7FFFFFFFFFFFFF) &&
             Value >= EBML_PRETTYLONGINT(-0x80000000000000)) {
    SetSize_(7);
  } else {
    SetSize_(8);
  }

  if (GetDefaultSize() > GetSize()) {
    SetSize_(GetDefaultSize());
  }

  return GetSize();
}

filepos_t EbmlSInteger::ReadData(IOCallback & input, ScopeMode ReadFully)
{
  if (ReadFully != SCOPE_NO_DATA) {
    binary Buffer[8];
    input.readFully(Buffer, GetSize());

    uint64_t TempValue = Buffer[0] & 0x80 ? std::numeric_limits<uint64_t>::max() : 0;

    for (unsigned int i=0; i<GetSize(); i++) {
      TempValue <<= 8;
      TempValue |= Buffer[i];
    }

    Value = ToSigned(TempValue);

    SetValueIsSet();
  }

  return GetSize();
}

bool EbmlSInteger::IsSmallerThan(const EbmlElement *Cmp) const
{
  if (EbmlId(*this) == EbmlId(*Cmp))
    return this->Value < static_cast<const EbmlSInteger *>(Cmp)->Value;
  else
    return false;
}

END_LIBEBML_NAMESPACE
<|endoftext|>


<commit_before>#include<iostream>
#include"Environments.hpp"
#include"version.hpp"
#include"fileutils.hpp"
#include"xml.hpp"

Environments::Environments(const QString path){
    if(QFile::exists(path)){
        this->path = path;
    }else{
        return;
    }
    QDir dir(this->path);
    QStringList envList = dir.entryList();
    MCEnv *p;

    this->updateEnvData();
}

int Environments::updateEnvData(){
    QDir dir(this->path);
    QStringList envList = dir.entryList(QDir::NoDotAndDotDot | QDir::AllDirs);
    MCEnv* p;
    for(int i = 0;i < envList.size();++i){
        bool dumpflg = false;
        //候補のディレクトリ直下にeachEnvDataXmlNameが存在しない場合はスキップする
        if(!QFile::exists(mcswitch_dir_env + fsp + envList.at(i) + fsp + eachEnvDataXmlName)) continue;
        //すでに同PATHを表すMCSWitchが登録されてるならスキップする
        for(int n = 0;n < this->getNumberOfEnvironments();++n){
            if(envsVector[n]->getName() == envList.at(i)){
                dumpflg = true;
            }
        }
        if(dumpflg == true){
            continue;
        }

        //上記２つに引っかからないものをMCSwitchの環境として認め登録
        p = new MCEnv(path + fsp + envList.at(i));
        if(!p->open()){
            std::cerr<<"IGNORE::Failed to read "<<(path + fsp +envList.at(i)).toStdString()<<std::endl;
            continue;
        }
        envsVector.push_back(p);

    }
    return getNumberOfEnvironments();
}

int Environments::getNumberOfEnvironments(){
    return envsVector.size();
}

MCEnv* Environments::getMCEnv(int n){
    if(n < 0 || n >= this->getNumberOfEnvironments()){
        return NULL;
    }else{
        return envsVector[n];
    }
}

MCEnv* Environments::getCurrentEnv(){
    Xml reader(minecraft_dir + "/" +  eachEnvDataXmlName);
    if(reader.open() == false){
        return NULL;
    }
    xml_d data;
    reader.getXmlData(&data);
    for(int i = 0;i < this->getNumberOfEnvironments();++i){
        if(envsVector[i]->getName() == data.name){
            return envsVector[i];
        }
    }
    return NULL;
}

bool Environments::createNewEnvironemnt(const QString name,int* v,const QString comment,bool usemod_f){
    if(!fileutils::rm_R(QString("/Users/opamp/Desktop/testdir"))){
        std::cout<<"失敗"<<std::endl;
    }
    init_d data;
    data.name = name;
    data.version[0] = *v;
    data.version[1] = *(v + 1);
    data.version[2] = *(v + 2);
    data.comment = comment;
    data.usemod = usemod_f;
    if(!MCEnv::initEnv(&data,mcswitch_dir_env))return false; // create new environment.
    return true;
}

bool Environments::installNewEnvironment(const QString name,const QString path){
    if(path.isEmpty() or !QDir().exists(path)) return false;
    QStringList envs = QDir(mcswitch_dir_env).entryList();
    QStringListIterator i(envs);
    while(i.hasNext()){
        if(i.next() == name){
            return false; //同名のEnvironemntがないかチェック
        }
    }

    if(!fileutils::cp_R(path, mcswitch_dir_env + fsp + name)) return false; //copy.

    /*以下のifの中でeachEnvDataXmlNameに入っている文字列で設定ファイルを生成*/
    if(QFile::exists(path + fsp + eachEnvDataXmlName)){
        QFile::remove(mcswitch_dir_env + fsp + name + fsp + eachEnvDataXmlName);
        QFile::copy(path + fsp + eachEnvDataXmlName,mcswitch_dir_env + fsp + name + fsp + eachEnvDataXmlName);
        QFile::setPermissions(mcswitch_dir_env + fsp + name + fsp + eachEnvDataXmlName,
                                  QFile::ReadOwner  |
                                  QFile::WriteOwner |
                                  QFile::ReadUser   |
                                  QFile::WriteUser
                                  );

    }else{
        if(!QFile::copy(tmp_xml1,mcswitch_dir_env + "/" + name + "/" + eachEnvDataXmlName)) return false;
        QFile::setPermissions(mcswitch_dir_env + "/" + name + "/" + eachEnvDataXmlName,
                              QFile::ReadOwner  |
                              QFile::WriteOwner |
                              QFile::ReadUser   |
                              QFile::WriteUser
                              );
    }
    return true;
}

bool Environments::removeEnvironment(const QString name){
    if(name.isEmpty()) return false;
    if(QDir().remove(mcswitch_dir_env + "/" + name)) return true;
    return false;
}

bool Environments::changeEnv(QString env_name){
    for(int n = 0;n < envsVector.size();++n){
        if(envsVector[n]->getName() == env_name){
            QFile::remove(minecraft_dir + "/" + eachEnvDataXmlName);
            QFile::copy(mcswitch_dir_env + "/" + env_name + "/" + eachEnvDataXmlName,minecraft_dir + "/" + eachEnvDataXmlName);
        }
    }
}
<commit_msg>Environmentのフォルダ名を変更してもxml内のnameが利用されるが、現在設定されてあるEnvironmentのフォルダ名が変更されるとminecraft_dirのシンボリックリンクが無効になるので 起動時に初期化エラーになる。(初期化されてるかをminecraft_dir/.mcswitch.xmlの存在で判定しているから) ということで後でなんとかしないと<commit_after>#include<iostream>
#include"Environments.hpp"
#include"version.hpp"
#include"fileutils.hpp"
#include"xml.hpp"

Environments::Environments(const QString path){
    if(QFile::exists(path)){
        this->path = path;
    }else{
        return;
    }
    QDir dir(this->path);
    QStringList envList = dir.entryList();
    MCEnv *p;

    this->updateEnvData();
}

int Environments::updateEnvData(){
    QDir dir(this->path);
    QStringList envList = dir.entryList(QDir::NoDotAndDotDot | QDir::AllDirs);
    MCEnv* p;
    for(int i = 0;i < envList.size();++i){
        bool dumpflg = false;
        //候補のディレクトリ直下にeachEnvDataXmlNameが存在しない場合はスキップする
        if(!QFile::exists(mcswitch_dir_env + fsp + envList.at(i) + fsp + eachEnvDataXmlName)) continue;
        //すでに同PATHを表すMCSWitchが登録されてるならスキップする
        for(int n = 0;n < this->getNumberOfEnvironments();++n){
            if(envsVector[n]->getName() == envList.at(i)){
                dumpflg = true;
            }
        }
        if(dumpflg == true){
            continue;
        }

        //上記２つに引っかからないものをMCSwitchの環境として認め登録
        p = new MCEnv(path + fsp + envList.at(i));
        if(!p->open()){
            std::cerr<<"IGNORE::Failed to read "<<(path + fsp +envList.at(i)).toStdString()<<std::endl;
            continue;
        }
        envsVector.push_back(p);

    }
    return getNumberOfEnvironments();
}

int Environments::getNumberOfEnvironments(){
    return envsVector.size();
}

MCEnv* Environments::getMCEnv(int n){
    if(n < 0 || n >= this->getNumberOfEnvironments()){
        return NULL;
    }else{
        return envsVector[n];
    }
}

MCEnv* Environments::getCurrentEnv(){
    Xml reader(minecraft_dir + fsp +  eachEnvDataXmlName);
    if(reader.open() == false){
        return NULL;
    }
    xml_d data;
    reader.getXmlData(&data);
    for(int i = 0;i < this->getNumberOfEnvironments();++i){
        if(envsVector[i]->getName() == data.name){
            return envsVector[i];
        }
    }
    return NULL;
}

bool Environments::createNewEnvironemnt(const QString name,int* v,const QString comment,bool usemod_f){
    init_d data;
    data.name = name;
    data.version[0] = *v;
    data.version[1] = *(v + 1);
    data.version[2] = *(v + 2);
    data.comment = comment;
    data.usemod = usemod_f;
    if(!MCEnv::initEnv(&data,mcswitch_dir_env))return false; // create new environment.
    return true;
}

bool Environments::installNewEnvironment(const QString name,const QString path){
    if(path.isEmpty() or !QDir().exists(path)) return false;
    QStringList envs = QDir(mcswitch_dir_env).entryList();
    QStringListIterator i(envs);
    while(i.hasNext()){
        if(i.next() == name){
            return false; //同名のEnvironemntがないかチェック
        }
    }

    if(!fileutils::cp_R(path, mcswitch_dir_env + fsp + name)) return false; //copy.

    /*以下のifの中でeachEnvDataXmlNameに入っている文字列で設定ファイルを生成*/
    if(QFile::exists(path + fsp + eachEnvDataXmlName)){
        QFile::remove(mcswitch_dir_env + fsp + name + fsp + eachEnvDataXmlName);
        QFile::copy(path + fsp + eachEnvDataXmlName,mcswitch_dir_env + fsp + name + fsp + eachEnvDataXmlName);
        QFile::setPermissions(mcswitch_dir_env + fsp + name + fsp + eachEnvDataXmlName,
                                  QFile::ReadOwner  |
                                  QFile::WriteOwner |
                                  QFile::ReadUser   |
                                  QFile::WriteUser
                                  );

    }else{
        if(!QFile::copy(tmp_xml1,mcswitch_dir_env + "/" + name + "/" + eachEnvDataXmlName)) return false;
        QFile::setPermissions(mcswitch_dir_env + "/" + name + "/" + eachEnvDataXmlName,
                              QFile::ReadOwner  |
                              QFile::WriteOwner |
                              QFile::ReadUser   |
                              QFile::WriteUser
                              );
    }
    return true;
}

bool Environments::removeEnvironment(const QString name){
    if(name.isEmpty()) return false;
    if(QDir().remove(mcswitch_dir_env + "/" + name)) return true;
    return false;
}

bool Environments::changeEnv(QString env_name){
    for(int n = 0;n < envsVector.size();++n){
        if(envsVector[n]->getName() == env_name){
            QFile::remove(minecraft_dir + "/" + eachEnvDataXmlName);
            QFile::copy(mcswitch_dir_env + "/" + env_name + "/" + eachEnvDataXmlName,minecraft_dir + "/" + eachEnvDataXmlName);
        }
    }
}
<|endoftext|>