<commit_before>/***********************************************************************
 query.cpp - Implements the Query class.

 Copyright (c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by
 MySQL AB, and (c) 2004, 2005 by Educational Technology Resources, Inc.
 Others may also hold copyrights on code in this file.  See the CREDITS
 file in the top directory of the distribution for details.

 This file is part of MySQL++.

 MySQL++ 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.

 MySQL++ 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 MySQL++; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
 USA
***********************************************************************/

#include "query.h"

namespace mysqlpp {

Query::Query(const Query& q) :
SQLQuery(q),
OptionalExceptions(q.exceptions()),
Lockable(),
conn_(q.conn_)
{
}

bool Query::exec(const std::string& str)
{
	Success = !mysql_real_query(&conn_->mysql, str.c_str(),
			str.length());
	if (!Success && throw_exceptions()) {
		throw BadQuery(conn_->error());
	}
	else {
		return Success;
	}
}

bool Query::success()
{
	if (Success) {
		return conn_->success();
	}
	else {
		return false;
	}
}

/// \if INTERNAL
// Doxygen will not generate documentation for this section.

ResNSel Query::execute(const char* str)
{
	Success = false;
	if (lock()) {
		if (throw_exceptions()) {
			throw BadQuery("lock failed");
		}
		else {
			return ResNSel();
		}
	}

	Success = !mysql_query(&conn_->mysql, str);
	unlock();
	if (Success) {
		return ResNSel(conn_);
	}
	else {
		if (throw_exceptions()) {
			throw BadQuery(conn_->error());
		}
		else {
			return ResNSel();
		}
	}
}

ResNSel Query::execute(parms& p)
{
	query_reset r = parsed.size() ? DONT_RESET : RESET_QUERY;
	return execute(str(p, r).c_str());
}

ResUse Query::use(const char* str)
{
	Success = false;
	if (lock()) {
		if (throw_exceptions()) {
			throw BadQuery("lock failed");
		}
		else {
			return ResUse();
		}
	}

	Success = !mysql_query(&conn_->mysql, str);
	if (Success) {
		MYSQL_RES* res = mysql_use_result(&conn_->mysql);
		if (res) {
			unlock();
			return ResUse(res, conn_, throw_exceptions());
		}
	}
	unlock();

	// One of the mysql_* calls failed, so decide how we should fail.
	if (throw_exceptions()) {
		throw BadQuery(conn_->error());
	}
	else {
		return ResUse();
	}
}

ResUse Query::use(parms& p)
{
	query_reset r = parsed.size() ? DONT_RESET : RESET_QUERY;
	return use(str(p, r).c_str());
}

Result Query::store(const char* str)
{
	Success = false;

	if (lock()) {
		if (throw_exceptions()) {
			throw BadQuery("lock failed");
		}
		else {
			return Result();
		}
	}

	Success = !mysql_query(&conn_->mysql, str);
	if (Success) {
		MYSQL_RES* res = mysql_store_result(&conn_->mysql);
		if (res) {
			unlock();
			return Result(res, throw_exceptions());
		}
	}
	unlock();

	// One of the mysql_* calls failed, so decide how we should fail.
	if (throw_exceptions()) {
		throw BadQuery(conn_->error());
	}
	else {
		return Result();
	}
}

Result Query::store(parms& p)
{
	query_reset r = parsed.size() ? DONT_RESET : RESET_QUERY;
	return store(str(p, r).c_str());
}

/// \endif

my_ulonglong Query::affected_rows() const
{
	return conn_->affected_rows();
}

my_ulonglong Query::insert_id()
{
	return conn_->insert_id();
}

std::string Query::info()
{
	return conn_->info();
}

std::string Query::error()
{
	if (errmsg) {
		return std::string(errmsg);
	}
	else {
		return conn_->error();
	}
}

bool Query::lock()
{
    return conn_->lock();
}

void Query::unlock()
{
	conn_->unlock();
}

} // end namespace mysqlpp

<commit_msg>Alphabetized functions in query.cpp.  This will make it clearer in the diff what came from where in coming SQLQuery merge.<commit_after>/***********************************************************************
 query.cpp - Implements the Query class.

 Copyright (c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by
 MySQL AB, and (c) 2004, 2005 by Educational Technology Resources, Inc.
 Others may also hold copyrights on code in this file.  See the CREDITS
 file in the top directory of the distribution for details.

 This file is part of MySQL++.

 MySQL++ 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.

 MySQL++ 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 MySQL++; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
 USA
***********************************************************************/

#include "query.h"

namespace mysqlpp {

Query::Query(const Query& q) :
SQLQuery(q),
OptionalExceptions(q.exceptions()),
Lockable(),
conn_(q.conn_)
{
}

my_ulonglong Query::affected_rows() const
{
	return conn_->affected_rows();
}

std::string Query::error()
{
	if (errmsg) {
		return std::string(errmsg);
	}
	else {
		return conn_->error();
	}
}

bool Query::exec(const std::string& str)
{
	Success = !mysql_real_query(&conn_->mysql, str.c_str(),
			str.length());
	if (!Success && throw_exceptions()) {
		throw BadQuery(conn_->error());
	}
	else {
		return Success;
	}
}

ResNSel Query::execute(const char* str)
{
	Success = false;
	if (lock()) {
		if (throw_exceptions()) {
			throw BadQuery("lock failed");
		}
		else {
			return ResNSel();
		}
	}

	Success = !mysql_query(&conn_->mysql, str);
	unlock();
	if (Success) {
		return ResNSel(conn_);
	}
	else {
		if (throw_exceptions()) {
			throw BadQuery(conn_->error());
		}
		else {
			return ResNSel();
		}
	}
}

ResNSel Query::execute(parms& p)
{
	query_reset r = parsed.size() ? DONT_RESET : RESET_QUERY;
	return execute(str(p, r).c_str());
}

std::string Query::info()
{
	return conn_->info();
}

my_ulonglong Query::insert_id()
{
	return conn_->insert_id();
}

bool Query::lock()
{
    return conn_->lock();
}

Result Query::store(const char* str)
{
	Success = false;

	if (lock()) {
		if (throw_exceptions()) {
			throw BadQuery("lock failed");
		}
		else {
			return Result();
		}
	}

	Success = !mysql_query(&conn_->mysql, str);
	if (Success) {
		MYSQL_RES* res = mysql_store_result(&conn_->mysql);
		if (res) {
			unlock();
			return Result(res, throw_exceptions());
		}
	}
	unlock();

	// One of the mysql_* calls failed, so decide how we should fail.
	if (throw_exceptions()) {
		throw BadQuery(conn_->error());
	}
	else {
		return Result();
	}
}

Result Query::store(parms& p)
{
	query_reset r = parsed.size() ? DONT_RESET : RESET_QUERY;
	return store(str(p, r).c_str());
}

bool Query::success()
{
	if (Success) {
		return conn_->success();
	}
	else {
		return false;
	}
}

void Query::unlock()
{
	conn_->unlock();
}

ResUse Query::use(const char* str)
{
	Success = false;
	if (lock()) {
		if (throw_exceptions()) {
			throw BadQuery("lock failed");
		}
		else {
			return ResUse();
		}
	}

	Success = !mysql_query(&conn_->mysql, str);
	if (Success) {
		MYSQL_RES* res = mysql_use_result(&conn_->mysql);
		if (res) {
			unlock();
			return ResUse(res, conn_, throw_exceptions());
		}
	}
	unlock();

	// One of the mysql_* calls failed, so decide how we should fail.
	if (throw_exceptions()) {
		throw BadQuery(conn_->error());
	}
	else {
		return ResUse();
	}
}

ResUse Query::use(parms& p)
{
	query_reset r = parsed.size() ? DONT_RESET : RESET_QUERY;
	return use(str(p, r).c_str());
}

} // end namespace mysqlpp

<|endoftext|>


<commit_before>// https://projecteuler.net/problem=68
/*
Magic 5-gon ring

Consider the following "magic" 3-gon ring, filled with the numbers 1 to 6, and each
line adding to nine.

   4
    \
     \
      3
     / \
    /   \
   1-----2-----6
  /
 /
5

Working clockwise, and starting from the group of three with the numerically lowest
external node (4,3,2 in this example), each solution can be described uniquely.
For example, the above solution can be described by the set: 4,3,2; 6,2,1; 5,1,3.

It is possible to complete the ring with four different totals: 9, 10, 11, and 12.
There are eight solutions in total.

Total	Solution Set
    9	4,2,3; 5,3,1; 6,1,2
	9	4,3,2; 6,2,1; 5,1,3
   10	2,3,5; 4,5,1; 6,1,3
   10	2,5,3; 6,3,1; 4,1,5
   11	1,4,6; 3,6,2; 5,2,4
   11	1,6,4; 5,4,2; 3,2,6
   12	1,5,6; 2,6,4; 3,4,5
   12	1,6,5; 3,5,4; 2,4,6

By concatenating each group it is possible to form 9-digit strings;
the maximum string for a 3-gon ring is 432621513.

Using the numbers 1 to 10, and depending on arrangements, it is possible to form 16-
and 17-digit strings. What is the maximum 16-digit string for a "magic" 5-gon ring?

Solution:
Create all possible pairs of adjacent internal nodes e.g. in case of 3-gon 1-2,1-3,1-4,
1-5,1-6, 2-1,2-3,2-4,... etc.
Given the sum create outer node as sum - total of pair of internal nodes. That will
create all the possible lines for the given sum. If the outer node is zero in the line
that means that line is impossible for the given sum.

Now, run a dfs by selecting 1 internal node at a time from the possible lines. Mask can
be used to avoid duplicate. An internal mask can also be used to avoid visiting different
rotations of the same solution.

*/

#include <iostream>
#include <cstdint>
#include <string>
#include <vector>
#include <set>
#include <algorithm>
#include <chrono>

std::vector<std::vector<int>> lines;
int polygon, maxNumber, imask;
std::vector<int> ngon;
std::set<std::string> solutions;

void addSolution() {
	using namespace std;
	vector<vector<int>> tbl;
	for (int i = 1; i < maxNumber; i += 2)
		tbl.push_back({ ngon[i], ngon[i - 1], ngon[(i + 1 < maxNumber) ? (i + 1) : 0] });

	auto idx = min_element(begin(tbl), end(tbl), [](const auto& a1, const auto& a2) {
		return a1[0] < a2[0];
	}) - begin(tbl);

	string rep;
	for (int i = 0; i < polygon; i++, idx = (idx + 1) % polygon)
		rep += to_string(tbl[idx][0]) + to_string(tbl[idx][1]) + to_string(tbl[idx][2]);
	solutions.insert(rep);
}

void dfs(int mask, int idx) {
	if (idx == maxNumber - 2) {
		const auto k = lines[ngon[idx]][ngon[0]];
		if (k && !(mask&(1 << k))) {
			ngon[idx + 1] = k;
			addSolution();
		}
		return;
	}

	for (int i = 1; i <= maxNumber; ++i) {
		if (!(mask & (1 << i)) && !(imask & (1 << i))) {
			const auto k = lines[ngon[idx]][i];
			if (k && !(mask&(1 << k))) {
				ngon[idx + 1] = k;
				ngon[idx + 2] = i;
				dfs(mask | (1 << i) | (1 << k), idx + 2);
			}
		}
	}
}

void generate(int sum) {
	solutions.clear();
	lines.clear();
	for (int i = 0; i <= maxNumber; ++i) {
		std::vector<int> line = { 0 };
		for (int j = 1; j <= maxNumber; ++j) {
			const int k = sum - i - j;
			line.push_back((k > 0 && k <= maxNumber && k != i && k != j) ? k : 0);
		}
		lines.emplace_back(line);
	}

	imask = 0;
	for (int i = 1; i <= polygon + 1; ++i) {
		ngon[0] = i;
		imask |= 1 << i;
		dfs(1 << i, 0);
	}
}

auto compute() {
	polygon = 5;
	maxNumber = 2 * polygon;
	ngon.resize(maxNumber);

	generate(14);
	std::string max;
	for (const auto& rep : solutions)
		if (rep.length() == 16 && rep > max)
			max = rep;
	return max;
}

int main() {
	using namespace std;
	using namespace chrono;
	auto start = high_resolution_clock::now();
	auto result = compute();
	cout << "Done in "
		<< duration_cast<nanoseconds>(high_resolution_clock::now() - start).count() / 1000000.0
		<< " miliseconds." << endl;
	cout << result << endl;
}<commit_msg>spacing in problem statement<commit_after>// https://projecteuler.net/problem=68
/*
Magic 5-gon ring

Consider the following "magic" 3-gon ring, filled with the numbers 1 to 6, and each
line adding to nine.

   4
    \
     \
      3
     / \
    /   \
   1-----2-----6
  /
 /
5

Working clockwise, and starting from the group of three with the numerically lowest
external node (4,3,2 in this example), each solution can be described uniquely.
For example, the above solution can be described by the set: 4,3,2; 6,2,1; 5,1,3.

It is possible to complete the ring with four different totals: 9, 10, 11, and 12.
There are eight solutions in total.

Total	Solution Set
    9	4,2,3; 5,3,1; 6,1,2
    9	4,3,2; 6,2,1; 5,1,3
   10	2,3,5; 4,5,1; 6,1,3
   10	2,5,3; 6,3,1; 4,1,5
   11	1,4,6; 3,6,2; 5,2,4
   11	1,6,4; 5,4,2; 3,2,6
   12	1,5,6; 2,6,4; 3,4,5
   12	1,6,5; 3,5,4; 2,4,6

By concatenating each group it is possible to form 9-digit strings;
the maximum string for a 3-gon ring is 432621513.

Using the numbers 1 to 10, and depending on arrangements, it is possible to form 16-
and 17-digit strings. What is the maximum 16-digit string for a "magic" 5-gon ring?

Solution:
Create all possible pairs of adjacent internal nodes e.g. in case of 3-gon 1-2,1-3,1-4,
1-5,1-6, 2-1,2-3,2-4,... etc.
Given the sum create outer node as sum - total of pair of internal nodes. That will
create all the possible lines for the given sum. If the outer node is zero in the line
that means that line is impossible for the given sum.

Now, run a dfs by selecting 1 internal node at a time from the possible lines. Mask can
be used to avoid duplicate. An internal mask can also be used to avoid visiting different
rotations of the same solution.

*/

#include <iostream>
#include <cstdint>
#include <string>
#include <vector>
#include <set>
#include <algorithm>
#include <chrono>

std::vector<std::vector<int>> lines;
int polygon, maxNumber, imask;
std::vector<int> ngon;
std::set<std::string> solutions;

void addSolution() {
	using namespace std;
	vector<vector<int>> tbl;
	for (int i = 1; i < maxNumber; i += 2)
		tbl.push_back({ ngon[i], ngon[i - 1], ngon[(i + 1 < maxNumber) ? (i + 1) : 0] });

	auto idx = min_element(begin(tbl), end(tbl), [](const auto& a1, const auto& a2) {
		return a1[0] < a2[0];
	}) - begin(tbl);

	string rep;
	for (int i = 0; i < polygon; i++, idx = (idx + 1) % polygon)
		rep += to_string(tbl[idx][0]) + to_string(tbl[idx][1]) + to_string(tbl[idx][2]);
	solutions.insert(rep);
}

void dfs(int mask, int idx) {
	if (idx == maxNumber - 2) {
		const auto k = lines[ngon[idx]][ngon[0]];
		if (k && !(mask&(1 << k))) {
			ngon[idx + 1] = k;
			addSolution();
		}
		return;
	}

	for (int i = 1; i <= maxNumber; ++i) {
		if (!(mask & (1 << i)) && !(imask & (1 << i))) {
			const auto k = lines[ngon[idx]][i];
			if (k && !(mask&(1 << k))) {
				ngon[idx + 1] = k;
				ngon[idx + 2] = i;
				dfs(mask | (1 << i) | (1 << k), idx + 2);
			}
		}
	}
}

void generate(int sum) {
	solutions.clear();
	lines.clear();
	for (int i = 0; i <= maxNumber; ++i) {
		std::vector<int> line = { 0 };
		for (int j = 1; j <= maxNumber; ++j) {
			const int k = sum - i - j;
			line.push_back((k > 0 && k <= maxNumber && k != i && k != j) ? k : 0);
		}
		lines.emplace_back(line);
	}

	imask = 0;
	for (int i = 1; i <= polygon + 1; ++i) {
		ngon[0] = i;
		imask |= 1 << i;
		dfs(1 << i, 0);
	}
}

auto compute() {
	polygon = 5;
	maxNumber = 2 * polygon;
	ngon.resize(maxNumber);

	generate(14);
	std::string max;
	for (const auto& rep : solutions)
		if (rep.length() == 16 && rep > max)
			max = rep;
	return max;
}

int main() {
	using namespace std;
	using namespace chrono;
	auto start = high_resolution_clock::now();
	auto result = compute();
	cout << "Done in "
		<< duration_cast<nanoseconds>(high_resolution_clock::now() - start).count() / 1000000.0
		<< " miliseconds." << endl;
	cout << result << endl;
}<|endoftext|>


<commit_before>//
// Created by Miguel Rentes on 30/01/2017.
//

#include "STL.h"

void printKMax(int arr[], int n, int k) {
    deque<int> mydeque;
    int greatest = 0;
    int value = 0;
    int index = 0;
    std::deque<int>::iterator it;
    for (int i = 0; i < n; i++) {
        mydeque.push_front(arr[i]);
    }
    for (int i = 0; i <= n-k; i++) {
        it = mydeque.begin();
        while (index < k) {
            value = *it;
            if (value > greatest)
                greatest = value;
            it++;
            index++;
        }
        mydeque.pop_front();
        mydeque.push_back(greatest);
        greatest = 0;
        index = 0;
    }
    for (int i = 0; i <= n-k; i++) {
        cout << mydeque.back() << " ";
        mydeque.pop_back();
    }
    cout << endl;
}

int main(void) {
    int t;
    cin >> t;
    while (t > 0) {
        int n, k;
        cin >> n >> k;
        int i;
        int arr[n];
        for (i = 0; i < n; i++)
            cin >> arr[i];
        printKMax(arr, n, k);
        t--;
    }
    return EXIT_SUCCESS;
}<commit_msg>Starts solution for the Deque-STL challenge.<commit_after>//
// Created by Miguel Rentes on 30/01/2017.
//

#include "STL.h"

void printKMax(int arr[], int n, int k) {
    deque<int> mydeque;
    int greatest = 0;
    int value = 0;
    int index = 0;
    int iteration = 0;
    // pushing all the greatest values on each k-elements to the front of the deque
    for (int i = 0; i < n; ) {
        if (index < k) {
            value = arr[i];
            if (value > greatest)
                greatest = value;
            if (index == k - 1) {
                mydeque.push_front(greatest);
                greatest = 0;
                index = 0;
                iteration++;
                i = iteration;
            } else {
                index++;
                i++;
            }
        }
    }
    // pop-ing the greatest values from the back of the deque
    while(mydeque.size() > 0) {
        cout << mydeque.back() << " ";
        mydeque.pop_back();
    }
    cout << endl;
}

int main(void) {
    int t;
    cin >> t;
    while (t > 0) {
        int n, k;
        cin >> n >> k;
        int i;
        int arr[n];
        for (i = 0; i < n; i++)
            cin >> arr[i];
        printKMax(arr, n, k);
        t--;
    }
    return EXIT_SUCCESS;
}<|endoftext|>


<commit_before>#include <osgTerrain/TerrainTile>
#include <osgDB/ObjectWrapper>
#include <osgDB/InputStream>
#include <osgDB/OutputStream>

// _tileID
static bool checkTileID( const osgTerrain::TerrainTile& tile )
{
    return tile.getTileID().valid();
}

static bool readTileID( osgDB::InputStream& is, osgTerrain::TerrainTile& tile )
{
    osgTerrain::TileID id;
    is >> id.level >> id.x >> id.y;
    tile.setTileID( id );
    return true;
}

static bool writeTileID( osgDB::OutputStream& os, const osgTerrain::TerrainTile& tile )
{
    const osgTerrain::TileID& id = tile.getTileID();
    os << id.level << id.x << id.y << std::endl;
    return true;
}

// _colorLayers
static bool checkColorLayers( const osgTerrain::TerrainTile& tile )
{
    return tile.getNumColorLayers()>0;
}

static bool readColorLayers( osgDB::InputStream& is, osgTerrain::TerrainTile& tile )
{
    unsigned int numValidLayers = 0; is >> numValidLayers >> osgDB::BEGIN_BRACKET;
    for ( unsigned int i=0; i<numValidLayers; ++i )
    {
        unsigned int layerNum=0; is >> osgDB::PROPERTY("Layer") >> layerNum;
        osgTerrain::Layer* layer = dynamic_cast<osgTerrain::Layer*>( is.readObject() );
        if ( layer ) tile.setColorLayer( layerNum, layer );
    }
    is >> osgDB::END_BRACKET;
    return true;
}

static bool writeColorLayers( osgDB::OutputStream& os, const osgTerrain::TerrainTile& tile )
{
    unsigned int numValidLayers = 0;
    for ( unsigned int i=0; i<tile.getNumColorLayers(); ++i )
    {
        if (tile.getColorLayer(i)) ++numValidLayers;
    }

    os << numValidLayers << osgDB::BEGIN_BRACKET << std::endl;
    for ( unsigned int i=0; i<tile.getNumColorLayers(); ++i )
    {
        if (tile.getColorLayer(i)) os << osgDB::PROPERTY("Layer") << i << tile.getColorLayer(i);
    }
    os << osgDB::END_BRACKET << std::endl;
    return true;
}

REGISTER_OBJECT_WRAPPER( osgTerrain_TerrainTile,
                         new osgTerrain::TerrainTile,
                         osgTerrain::TerrainTile,
                         "osg::Object osg::Node osg::Group osgTerrain::TerrainTile" )
{
    ADD_USER_SERIALIZER( TileID );  // _tileID
    ADD_OBJECT_SERIALIZER( TerrainTechnique, osgTerrain::TerrainTechnique, NULL );  // _terrainTechnique
    ADD_OBJECT_SERIALIZER( Locator, osgTerrain::Locator, NULL );  // _locator
    ADD_OBJECT_SERIALIZER( ElevationLayer, osgTerrain::Layer, NULL );  // _elevationLayer
    ADD_USER_SERIALIZER( ColorLayers );  // _colorLayers
    ADD_BOOL_SERIALIZER( RequiresNormals, true );  // _requiresNormals
    ADD_BOOL_SERIALIZER( TreatBoundariesToValidDataAsDefaultValue, false );  // _treatBoundariesToValidDataAsDefaultValue
    BEGIN_ENUM_SERIALIZER( BlendingPolicy, INHERIT );
        ADD_ENUM_VALUE( INHERIT );
        ADD_ENUM_VALUE( DO_NOT_SET_BLENDING );
        ADD_ENUM_VALUE( ENABLE_BLENDING );
        ADD_ENUM_VALUE( ENABLE_BLENDING_WHEN_ALPHA_PRESENT );
    END_ENUM_SERIALIZER();  // BlendingPolicy
}
<commit_msg>From Wang Rui, "A solution for serialziers to call static functions at the end of reading/writing is to use a user serializer. The serialziers/osgManipulator/Draggers.cpp uses a DefaultGeometry serializer to run setupDefaultGeometry() once the reading process is finished, and this can also be applied to load the TerrainTileCallback.<commit_after>#include <osgTerrain/TerrainTile>
#include <osgDB/ObjectWrapper>
#include <osgDB/InputStream>
#include <osgDB/OutputStream>

// _tileID
static bool checkTileID( const osgTerrain::TerrainTile& tile )
{
    return tile.getTileID().valid();
}

static bool readTileID( osgDB::InputStream& is, osgTerrain::TerrainTile& tile )
{
    osgTerrain::TileID id;
    is >> id.level >> id.x >> id.y;
    tile.setTileID( id );
    return true;
}

static bool writeTileID( osgDB::OutputStream& os, const osgTerrain::TerrainTile& tile )
{
    const osgTerrain::TileID& id = tile.getTileID();
    os << id.level << id.x << id.y << std::endl;
    return true;
}

// _colorLayers
static bool checkColorLayers( const osgTerrain::TerrainTile& tile )
{
    return tile.getNumColorLayers()>0;
}

static bool readColorLayers( osgDB::InputStream& is, osgTerrain::TerrainTile& tile )
{
    unsigned int numValidLayers = 0; is >> numValidLayers >> osgDB::BEGIN_BRACKET;
    for ( unsigned int i=0; i<numValidLayers; ++i )
    {
        unsigned int layerNum=0; is >> osgDB::PROPERTY("Layer") >> layerNum;
        osgTerrain::Layer* layer = dynamic_cast<osgTerrain::Layer*>( is.readObject() );
        if ( layer ) tile.setColorLayer( layerNum, layer );
    }
    is >> osgDB::END_BRACKET;
    return true;
}

static bool writeColorLayers( osgDB::OutputStream& os, const osgTerrain::TerrainTile& tile )
{
    unsigned int numValidLayers = 0;
    for ( unsigned int i=0; i<tile.getNumColorLayers(); ++i )
    {
        if (tile.getColorLayer(i)) ++numValidLayers;
    }

    os << numValidLayers << osgDB::BEGIN_BRACKET << std::endl;
    for ( unsigned int i=0; i<tile.getNumColorLayers(); ++i )
    {
        if (tile.getColorLayer(i)) os << osgDB::PROPERTY("Layer") << i << tile.getColorLayer(i);
    }
    os << osgDB::END_BRACKET << std::endl;
    return true;
}

// TileLoadedCallback
static bool checkTileLoadedCallback( const osgTerrain::TerrainTile& tile )
{ return true; }

static bool readTileLoadedCallback( osgDB::InputStream& is, osgTerrain::TerrainTile& tile )
{
    if ( osgTerrain::TerrainTile::getTileLoadedCallback().valid() )
        osgTerrain::TerrainTile::getTileLoadedCallback()->loaded( &terrainTile, is.getOptions() );
    return true;
}

static bool writeTileLoadedCallback( osgDB::OutputStream& os, const osgTerrain::TerrainTile& tile )
{ return true; }

REGISTER_OBJECT_WRAPPER( osgTerrain_TerrainTile,
                         new osgTerrain::TerrainTile,
                         osgTerrain::TerrainTile,
                         "osg::Object osg::Node osg::Group osgTerrain::TerrainTile" )
{
    ADD_USER_SERIALIZER( TileID );  // _tileID
    ADD_OBJECT_SERIALIZER( TerrainTechnique, osgTerrain::TerrainTechnique, NULL );  // _terrainTechnique
    ADD_OBJECT_SERIALIZER( Locator, osgTerrain::Locator, NULL );  // _locator
    ADD_OBJECT_SERIALIZER( ElevationLayer, osgTerrain::Layer, NULL );  // _elevationLayer
    ADD_USER_SERIALIZER( ColorLayers );  // _colorLayers
    ADD_BOOL_SERIALIZER( RequiresNormals, true );  // _requiresNormals
    ADD_BOOL_SERIALIZER( TreatBoundariesToValidDataAsDefaultValue, false );  // _treatBoundariesToValidDataAsDefaultValue
    BEGIN_ENUM_SERIALIZER( BlendingPolicy, INHERIT );
        ADD_ENUM_VALUE( INHERIT );
        ADD_ENUM_VALUE( DO_NOT_SET_BLENDING );
        ADD_ENUM_VALUE( ENABLE_BLENDING );
        ADD_ENUM_VALUE( ENABLE_BLENDING_WHEN_ALPHA_PRESENT );
    END_ENUM_SERIALIZER();  // BlendingPolicy

    ADD_USER_SERIALIZER( TileLoadedCallback );
}
<|endoftext|>


<commit_before><commit_msg>If you select a date like Jan 31, and you go to a month with less days than that date, show the last day of the new month instead of doing nothing.<commit_after><|endoftext|>


<commit_before>// @(#)root/base:$Id$
// Author: Bertrand Bellenot   19/06/2007

/*************************************************************************
 * Copyright (C) 1995-2007, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TRemoteObject                                                        //
//                                                                      //
// The TRemoteObject class provides protocol for browsing ROOT objects  //
// from a remote ROOT session.                                          //
// It contains informations on the real remote object as:               //
//  - Object Properties (i.e. file stat if the object is a TSystemFile) //
//  - Object Name                                                       //
//  - Class Name                                                        //
//  - TKey Object Name (if the remote object is a TKey)                 //
//  - TKey Class Name (if the remote object is a TKey)                  //
//  - Remote object address                                             //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TApplication.h"
#include "TROOT.h"
#include "TRemoteObject.h"
#include "TSystem.h"
#include "TBrowser.h"
#include "TOrdCollection.h"
#include "TList.h"
#include "TClass.h"

ClassImp(TRemoteObject);

//______________________________________________________________________________
TRemoteObject::TRemoteObject()
{
   // Create a remote object.

   fIsFolder = kFALSE;
   fRemoteAddress = 0;
}

//______________________________________________________________________________
TRemoteObject::TRemoteObject(const char *name, const char *title,
                             const char *classname) : TNamed(name, title)
{
   // Create a remote object.

   fIsFolder = kFALSE;
   fClassName = classname;
   if ((fClassName == "TSystemDirectory") ||
       (fClassName == "TFile"))
      fIsFolder = kTRUE;
   if (!strcmp(classname, "TSystemDirectory") ||
       !strcmp(classname, "TSystemFile")) {
      gSystem->GetPathInfo(name, fFileStat);
   }
   Long_t raddr = (Long_t) this;
   fRemoteAddress = raddr;
}

//______________________________________________________________________________
TRemoteObject::~TRemoteObject()
{
   // Delete remote object.

}

//______________________________________________________________________________
void TRemoteObject::Browse(TBrowser *b)
{
   // Browse remote object.

   TList *ret;
   TRemoteObject *robj;
   const char *file;

   if (fClassName == "TSystemFile") {
      if (b)
         b->ExecuteDefaultAction(this);
      return;
   }
   if (fClassName == "TKey") {
      if (b->GetRefreshFlag())
         b->SetRefreshFlag(kFALSE);
      gApplication->SetBit(TApplication::kProcessRemotely);
      TObject *obj = (TObject *)gROOT->ProcessLine(Form("((TApplicationServer *)gApplication)->BrowseKey(\"%s\");", GetName()));
      if (b && obj) {
         if (obj->IsA()->GetMethodWithPrototype("SetDirectory", "TDirectory*"))
            gROOT->ProcessLine(Form("((%s *)0x%lx)->SetDirectory(0);", obj->ClassName(), (ULong_t)obj));
         obj->Browse(b);
         b->SetRefreshFlag(kTRUE);
      }
   }
   if (fClassName == "TSystemDirectory") {
      if (b->GetRefreshFlag())
         b->SetRefreshFlag(kFALSE);
      gApplication->SetBit(TApplication::kProcessRemotely);
      ret = (TList *)gROOT->ProcessLine(Form("((TApplicationServer *)gApplication)->BrowseDirectory(\"%s\");", GetTitle()));
      if (ret) {
         TIter next(ret);
         while ((robj = (TRemoteObject *)next())) {
            file = robj->GetName();
            if (b->TestBit(TBrowser::kNoHidden) && file[0] == '.' && file[1] != '.' )
               continue;
            b->Add(robj, robj->GetName());
         }
      }
      return;
   }
   if (fClassName == "TFile") {
      if (b->GetRefreshFlag())
         b->SetRefreshFlag(kFALSE);
      gApplication->SetBit(TApplication::kProcessRemotely);
      ret = (TList *)gROOT->ProcessLine(Form("((TApplicationServer *)gApplication)->BrowseFile(\"%s\");", GetName()));
      if (ret) {
         TIter next(ret);
         while ((robj = (TRemoteObject *)next())) {
            //file = robj->GetName();
            b->Add(robj, robj->GetName());
         }
      }
      return;
   }
}

//______________________________________________________________________________
TList *TRemoteObject::Browse()
{
   // Browse OS system directories.

   // Collections to keep track of all browser objects that have been
   // generated. It's main goal is to prevent the contineous
   // allocations of new objects with the same names during browsing.
   TList *objects  = new TList;

   static Int_t level = 0;
   const char *name = GetTitle();
   TRemoteObject *sdir;

   if (GetName()[0] == '.' && GetName()[1] == '.')
      SetName(gSystem->BaseName(name));

   TSystemDirectory dir(name, name);
   TList *files = dir.GetListOfFiles();
   if (files) {
      files->Sort();
      TIter next(files);
      TSystemFile *file;
      TString fname;
      // directories first
      while ((file=(TSystemFile*)next())) {
         fname = file->GetName();
         if (file->IsDirectory()) {
            level++;
            TString sdirpath;
            if (!strcmp(fname.Data(), "."))
               sdirpath = name;
            else if (!strcmp(fname.Data(), ".."))
               sdirpath = gSystem->DirName(name);
            else {
               sdirpath =  name;
               if (!sdirpath.EndsWith("/"))
                  sdirpath += "/";
               sdirpath += fname.Data();
            }
            sdir = new TRemoteObject(fname.Data(), sdirpath.Data(), "TSystemDirectory");
            objects->Add(sdir);
            level--;
         }
      }
      // then files...
      TIter nextf(files);
      while ((file=(TSystemFile*)nextf())) {
         fname = file->GetName();
         if (!file->IsDirectory()) {
            sdir = new TRemoteObject(fname.Data(), gSystem->WorkingDirectory(), "TSystemFile");
            objects->Add(sdir);
         }
      }
      delete files;
   }
   return objects;
}

//______________________________________________________________________________
Bool_t TRemoteObject::GetFileStat(FileStat_t *buf)
{
   // Get remote file status.

   buf->fDev    = fFileStat.fDev;
   buf->fIno    = fFileStat.fIno;
   buf->fMode   = fFileStat.fMode;
   buf->fUid    = fFileStat.fUid;
   buf->fGid    = fFileStat.fGid;
   buf->fSize   = fFileStat.fSize;
   buf->fMtime  = fFileStat.fMtime;
   buf->fIsLink = fFileStat.fIsLink;
   return kTRUE;
}

//______________________________________________________________________________
void TRemoteObject::Streamer(TBuffer &b)
{
   // Remote object streamer.

   if (b.IsReading()) {
      b >> fFileStat.fDev;
      b >> fFileStat.fIno;
      b >> fFileStat.fMode;
      b >> fFileStat.fUid;
      b >> fFileStat.fGid;
      b >> fFileStat.fSize;
      b >> fFileStat.fMtime;
      b >> fFileStat.fIsLink;
      b >> fIsFolder;
      b >> fRemoteAddress;
      b >> fClassName;
      b >> fKeyObjectName;
      b >> fKeyClassName;
   }
   else {
      b << fFileStat.fDev;
      b << fFileStat.fIno;
      b << fFileStat.fMode;
      b << fFileStat.fUid;
      b << fFileStat.fGid;
      b << fFileStat.fSize;
      b << fFileStat.fMtime;
      b << fFileStat.fIsLink;
      b << fIsFolder;
      b << fRemoteAddress;
      b << fClassName;
      b << fKeyObjectName;
      b << fKeyClassName;
   }
   TNamed::Streamer(b);
}
<commit_msg>fix coverity 10701.<commit_after>// @(#)root/base:$Id$
// Author: Bertrand Bellenot   19/06/2007

/*************************************************************************
 * Copyright (C) 1995-2007, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TRemoteObject                                                        //
//                                                                      //
// The TRemoteObject class provides protocol for browsing ROOT objects  //
// from a remote ROOT session.                                          //
// It contains informations on the real remote object as:               //
//  - Object Properties (i.e. file stat if the object is a TSystemFile) //
//  - Object Name                                                       //
//  - Class Name                                                        //
//  - TKey Object Name (if the remote object is a TKey)                 //
//  - TKey Class Name (if the remote object is a TKey)                  //
//  - Remote object address                                             //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TApplication.h"
#include "TROOT.h"
#include "TRemoteObject.h"
#include "TSystem.h"
#include "TBrowser.h"
#include "TOrdCollection.h"
#include "TList.h"
#include "TClass.h"

ClassImp(TRemoteObject);

//______________________________________________________________________________
TRemoteObject::TRemoteObject()
{
   // Create a remote object.

   fIsFolder = kFALSE;
   fRemoteAddress = 0;
}

//______________________________________________________________________________
TRemoteObject::TRemoteObject(const char *name, const char *title,
                             const char *classname) : TNamed(name, title)
{
   // Create a remote object.

   fIsFolder = kFALSE;
   fClassName = classname;
   if ((fClassName == "TSystemDirectory") ||
       (fClassName == "TFile"))
      fIsFolder = kTRUE;
   if (!strcmp(classname, "TSystemDirectory") ||
       !strcmp(classname, "TSystemFile")) {
      gSystem->GetPathInfo(name, fFileStat);
   }
   Long_t raddr = (Long_t) this;
   fRemoteAddress = raddr;
}

//______________________________________________________________________________
TRemoteObject::~TRemoteObject()
{
   // Delete remote object.

}

//______________________________________________________________________________
void TRemoteObject::Browse(TBrowser *b)
{
   // Browse remote object.

   TList *ret;
   TRemoteObject *robj;
   const char *file;

   if (fClassName == "TSystemFile") {
      if (b)
         b->ExecuteDefaultAction(this);
      return;
   }
   if (fClassName == "TKey") {
      if (b->GetRefreshFlag())
         b->SetRefreshFlag(kFALSE);
      gApplication->SetBit(TApplication::kProcessRemotely);
      TObject *obj = (TObject *)gROOT->ProcessLine(Form("((TApplicationServer *)gApplication)->BrowseKey(\"%s\");", GetName()));
      if (obj) {
         if (obj->IsA()->GetMethodWithPrototype("SetDirectory", "TDirectory*"))
            gROOT->ProcessLine(Form("((%s *)0x%lx)->SetDirectory(0);", obj->ClassName(), (ULong_t)obj));
         obj->Browse(b);
         b->SetRefreshFlag(kTRUE);
      }
   }
   if (fClassName == "TSystemDirectory") {
      if (b->GetRefreshFlag())
         b->SetRefreshFlag(kFALSE);
      gApplication->SetBit(TApplication::kProcessRemotely);
      ret = (TList *)gROOT->ProcessLine(Form("((TApplicationServer *)gApplication)->BrowseDirectory(\"%s\");", GetTitle()));
      if (ret) {
         TIter next(ret);
         while ((robj = (TRemoteObject *)next())) {
            file = robj->GetName();
            if (b->TestBit(TBrowser::kNoHidden) && file[0] == '.' && file[1] != '.' )
               continue;
            b->Add(robj, robj->GetName());
         }
      }
      return;
   }
   if (fClassName == "TFile") {
      if (b->GetRefreshFlag())
         b->SetRefreshFlag(kFALSE);
      gApplication->SetBit(TApplication::kProcessRemotely);
      ret = (TList *)gROOT->ProcessLine(Form("((TApplicationServer *)gApplication)->BrowseFile(\"%s\");", GetName()));
      if (ret) {
         TIter next(ret);
         while ((robj = (TRemoteObject *)next())) {
            //file = robj->GetName();
            b->Add(robj, robj->GetName());
         }
      }
      return;
   }
}

//______________________________________________________________________________
TList *TRemoteObject::Browse()
{
   // Browse OS system directories.

   // Collections to keep track of all browser objects that have been
   // generated. It's main goal is to prevent the contineous
   // allocations of new objects with the same names during browsing.
   TList *objects  = new TList;

   static Int_t level = 0;
   const char *name = GetTitle();
   TRemoteObject *sdir;

   if (GetName()[0] == '.' && GetName()[1] == '.')
      SetName(gSystem->BaseName(name));

   TSystemDirectory dir(name, name);
   TList *files = dir.GetListOfFiles();
   if (files) {
      files->Sort();
      TIter next(files);
      TSystemFile *file;
      TString fname;
      // directories first
      while ((file=(TSystemFile*)next())) {
         fname = file->GetName();
         if (file->IsDirectory()) {
            level++;
            TString sdirpath;
            if (!strcmp(fname.Data(), "."))
               sdirpath = name;
            else if (!strcmp(fname.Data(), ".."))
               sdirpath = gSystem->DirName(name);
            else {
               sdirpath =  name;
               if (!sdirpath.EndsWith("/"))
                  sdirpath += "/";
               sdirpath += fname.Data();
            }
            sdir = new TRemoteObject(fname.Data(), sdirpath.Data(), "TSystemDirectory");
            objects->Add(sdir);
            level--;
         }
      }
      // then files...
      TIter nextf(files);
      while ((file=(TSystemFile*)nextf())) {
         fname = file->GetName();
         if (!file->IsDirectory()) {
            sdir = new TRemoteObject(fname.Data(), gSystem->WorkingDirectory(), "TSystemFile");
            objects->Add(sdir);
         }
      }
      delete files;
   }
   return objects;
}

//______________________________________________________________________________
Bool_t TRemoteObject::GetFileStat(FileStat_t *buf)
{
   // Get remote file status.

   buf->fDev    = fFileStat.fDev;
   buf->fIno    = fFileStat.fIno;
   buf->fMode   = fFileStat.fMode;
   buf->fUid    = fFileStat.fUid;
   buf->fGid    = fFileStat.fGid;
   buf->fSize   = fFileStat.fSize;
   buf->fMtime  = fFileStat.fMtime;
   buf->fIsLink = fFileStat.fIsLink;
   return kTRUE;
}

//______________________________________________________________________________
void TRemoteObject::Streamer(TBuffer &b)
{
   // Remote object streamer.

   if (b.IsReading()) {
      b >> fFileStat.fDev;
      b >> fFileStat.fIno;
      b >> fFileStat.fMode;
      b >> fFileStat.fUid;
      b >> fFileStat.fGid;
      b >> fFileStat.fSize;
      b >> fFileStat.fMtime;
      b >> fFileStat.fIsLink;
      b >> fIsFolder;
      b >> fRemoteAddress;
      b >> fClassName;
      b >> fKeyObjectName;
      b >> fKeyClassName;
   }
   else {
      b << fFileStat.fDev;
      b << fFileStat.fIno;
      b << fFileStat.fMode;
      b << fFileStat.fUid;
      b << fFileStat.fGid;
      b << fFileStat.fSize;
      b << fFileStat.fMtime;
      b << fFileStat.fIsLink;
      b << fIsFolder;
      b << fRemoteAddress;
      b << fClassName;
      b << fKeyObjectName;
      b << fKeyClassName;
   }
   TNamed::Streamer(b);
}
<|endoftext|>


<commit_before><commit_msg>Continuing to define the bookkeeping<commit_after><|endoftext|>


<commit_before>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2017.  All rights reserved
 */
#include "../../../StroikaPreComp.h"

#include "../../../Characters/Format.h"

#include "Reader.h"

//// SEEE http://www.zlib.net/zlib_how.html
/// THIS SHOWS PRETTY SIMPLE EXAMPLE OF HOW TO DO COMPRESS/DECOMPRESS AND WE CAN USE THAT to amke new stream object
/// where inner loop is done each time through with a CHUNK

#if qHasFeature_ZLib
#include <zlib.h>

#if defined(_MSC_VER)
// Use #pragma comment lib instead of explicit entry in the lib entry of the project file
#pragma comment(lib, "zlib.lib")
#endif

using namespace Stroika::Foundation;
using namespace Stroika::Foundation::DataExchange;
using namespace Stroika::Foundation::DataExchange::Compression;
using namespace Stroika::Foundation::Streams;

// Comment this in to turn on aggressive noisy DbgTrace in this module
//#define   USE_NOISY_TRACE_IN_THIS_MODULE_       1

namespace {

    void ThrowIfZLibErr_ (int err)
    {
        // VERY ROUGH DRAFT - probably need a more specific exception object type
        if (err != Z_OK) {
            switch (err) {
                case Z_VERSION_ERROR:
                    Execution::Throw (Execution::StringException (L"ZLIB Z_VERSION_ERROR"));
                case Z_DATA_ERROR:
                    Execution::Throw (Execution::StringException (L"ZLIB Z_DATA_ERROR"));
                case Z_ERRNO:
                    Execution::Throw (Execution::StringException (Characters::Format (L"ZLIB Z_ERRNO (errno=%d", errno)));
                default:
                    Execution::Throw (Execution::StringException (Characters::Format (L"ZLIB ERR %d", err)));
            }
        }
    }

    using Memory::Byte;
    struct MyCompressionStream_ : InputStream<Byte>::Ptr {
        struct BaseRep_ : public InputStream<Byte>::_IRep {
            static constexpr size_t                 CHUNK = 16384;
            Streams::InputStream<Memory::Byte>::Ptr fInStream_;
            z_stream                                fZStream_;
            Byte                                    fInBuf_[CHUNK];
            SeekOffsetType                          _fSeekOffset{};
            BaseRep_ (const Streams::InputStream<Memory::Byte>::Ptr& in)
                : fInStream_ (in)
                , fZStream_{}
            {
            }
            virtual ~BaseRep_ () = default;
            virtual bool IsSeekable () const override
            {
                // for now - KISS
                return false; // SHOULD allow seekable IFF src is seekable
            }
            virtual void CloseRead () override
            {
                Require (IsOpenRead ());
                fInStream_.Close ();
                Assert (fInStream_ == nullptr);
                Ensure (not IsOpenRead ());
            }
            virtual bool IsOpenRead () const
            {
                return fInStream_ != nullptr;
            }
            virtual SeekOffsetType GetReadOffset () const override
            {
                return _fSeekOffset;
            }
            virtual SeekOffsetType SeekRead (Whence whence, SignedSeekOffsetType offset) override
            {
                RequireNotReached ();
                return SeekOffsetType{};
            }
            nonvirtual bool _AssureInputAvailableReturnTrueIfAtEOF ()
            {
                if (fZStream_.avail_in == 0) {
                    Assert (NEltsOf (fInBuf_) < numeric_limits<uInt>::max ());
                    fZStream_.avail_in = static_cast<uInt> (fInStream_.Read (begin (fInBuf_), end (fInBuf_)));
                    fZStream_.next_in  = begin (fInBuf_);
                }
                return fZStream_.avail_in == 0;
            }
        };
        struct DeflateRep_ : BaseRep_ {
            DeflateRep_ (const Streams::InputStream<Memory::Byte>::Ptr& in)
                : BaseRep_ (in)
            {
                int level = Z_DEFAULT_COMPRESSION;
                ThrowIfZLibErr_ (::deflateInit (&fZStream_, level));
            }
            virtual ~DeflateRep_ ()
            {
                Verify (::deflateEnd (&fZStream_) == Z_OK);
            }
            virtual size_t Read (ElementType* intoStart, ElementType* intoEnd) override
            {
                Require (intoStart < intoEnd); // API rule for streams
            Again:
                bool isAtSrcEOF = _AssureInputAvailableReturnTrueIfAtEOF ();

                Require (intoStart < intoEnd);
                ptrdiff_t outBufSize = intoEnd - intoStart;

                int flush = isAtSrcEOF ? Z_FINISH : Z_NO_FLUSH;

                fZStream_.avail_out = static_cast<uInt> (outBufSize);
                fZStream_.next_out  = intoStart;
                int ret;
                switch (ret = ::deflate (&fZStream_, flush)) {
                    case Z_OK:
                        break;
                    case Z_STREAM_END:
                        break;
                    default:
                        ThrowIfZLibErr_ (ret);
                }

                ptrdiff_t pulledOut = outBufSize - fZStream_.avail_out;
                Assert (pulledOut <= outBufSize);
                if (pulledOut == 0 and not isAtSrcEOF and flush == Z_NO_FLUSH) {
                    goto Again;
                }
                _fSeekOffset += pulledOut;
                return pulledOut;
            }
            virtual Memory::Optional<size_t> ReadNonBlocking (ElementType* intoStart, ElementType* intoEnd) override
            {
                Require ((intoStart == nullptr and intoEnd == nullptr) or (intoEnd - intoStart) >= 1);
// https://stroika.atlassian.net/browse/STK-567 EXPERIMENTAL DRAFT API - INCOMPLETE IMPL
#if 0
                if (intoStart == nullptr) {
                    // Just check if any data available

                }
                else {
                    Assert (intoStart < intoEnd);
                Again:
                    if (fZStream_.avail_in == 0) {
                        Assert (NEltsOf (fInBuf_) < numeric_limits<uInt>::max ());
                        if (auto o = fInStream_.ReadNonBlocking (begin (fInBuf_), end (fInBuf_))) {
                            fZStream_.avail_in = static_cast<uInt> (*o);
                            fZStream_.next_in = begin (fInBuf_);
                        }
                        else {
                            return {};
                        }
                    }
                    ptrdiff_t outBufSize = intoEnd - intoStart;
                    fZStream_.avail_out = static_cast<uInt> (outBufSize);
                    fZStream_.next_out = intoStart;
                    bool isAtSrcEOF = fZStream_.avail_in == 0;
                    int flush = isAtSrcEOF ? Z_FINISH : Z_NO_FLUSH;
                    int ret;
                    switch (ret = ::deflate (&fZStream_, flush)) {
                    case Z_OK:
                        break;
                    case Z_STREAM_END:
                        break;
                    default:
                        ThrowIfZLibErr_ (ret);
                    }
                    ptrdiff_t pulledOut = outBufSize - fZStream_.avail_out;
                    Assert (pulledOut <= outBufSize);
                    if (pulledOut == 0 and not isAtSrcEOF) {
                        goto Again;
                    }
                    _fSeekOffset += pulledOut;
                    return pulledOut;
                }
#else
                // INCOMPLETE - tricky... most common cases easy, but edges hard...
                if (fZStream_.avail_out == 0) {
                    if (fZStream_.avail_in == 0) {
                        if (Memory::Optional<size_t> tmpAvail = fInStream_.ReadNonBlocking (begin (fInBuf_), end (fInBuf_))) {
                        }
                        else {
                            return {};
                        }
                    }
                }
#endif
                WeakAssert (false);
                // @todo - FIX TO REALLY CHECK
                return {};
            }
        };
        struct InflateRep_ : BaseRep_ {
            InflateRep_ (const Streams::InputStream<Memory::Byte>::Ptr& in)
                : BaseRep_ (in)
            {
                // see http://zlib.net/manual.html  for meaning of params and http://www.lemoda.net/c/zlib-open-read/ for example
                constexpr int windowBits       = 15;
                constexpr int ENABLE_ZLIB_GZIP = 32;
                ThrowIfZLibErr_ (::inflateInit2 (&fZStream_, windowBits | ENABLE_ZLIB_GZIP));
            }
            virtual ~InflateRep_ ()
            {
                Verify (::inflateEnd (&fZStream_) == Z_OK);
            }
            virtual size_t Read (ElementType* intoStart, ElementType* intoEnd) override
            {
                Require (intoStart < intoEnd); // API rule for streams
            Again:
                bool      isAtSrcEOF = _AssureInputAvailableReturnTrueIfAtEOF ();
                ptrdiff_t outBufSize = intoEnd - intoStart;

                fZStream_.avail_out = static_cast<uInt> (outBufSize);
                fZStream_.next_out  = intoStart;
                int ret;
                switch (ret = ::inflate (&fZStream_, Z_NO_FLUSH)) {
                    case Z_OK:
                        break;
                    case Z_STREAM_END:
                        break;
                    default:
                        ThrowIfZLibErr_ (ret);
                }

                ptrdiff_t pulledOut = outBufSize - fZStream_.avail_out;
                Assert (pulledOut <= outBufSize);
                if (pulledOut == 0 and not isAtSrcEOF) {
                    goto Again;
                }
                _fSeekOffset += pulledOut;
                return pulledOut;
            }
            virtual Memory::Optional<size_t> ReadNonBlocking (ElementType* intoStart, ElementType* intoEnd) override
            {
                // https://stroika.atlassian.net/browse/STK-567 EXPERIMENTAL DRAFT API - incomplete IMPL
                Require ((intoStart == nullptr and intoEnd == nullptr) or (intoEnd - intoStart) >= 1);
                WeakAssert (false);
                // @todo - FIX TO REALLY CHECK
                return {};
            }
        };
        enum Compression { eCompression };
        enum DeCompression { eDeCompression };
        MyCompressionStream_ (Compression, const Streams::InputStream<Memory::Byte>::Ptr& in)
            : InputStream<Byte>::Ptr (make_shared<DeflateRep_> (in))
        {
        }
        MyCompressionStream_ (DeCompression, const Streams::InputStream<Memory::Byte>::Ptr& in)
            : InputStream<Byte>::Ptr (make_shared<InflateRep_> (in))
        {
        }
    };
}
#endif

#if qHasFeature_ZLib
class Zip::Reader::Rep_ : public Reader::_IRep {
public:
    virtual InputStream<Byte>::Ptr Compress (const InputStream<Byte>::Ptr& src) const override
    {
        return MyCompressionStream_ (MyCompressionStream_::eCompression, src);
    }
    virtual InputStream<Byte>::Ptr Decompress (const InputStream<Byte>::Ptr& src) const override
    {
        return MyCompressionStream_ (MyCompressionStream_::eDeCompression, src);
    }
};

Zip::Reader::Reader ()
    : DataExchange::Compression::Reader (make_shared<Rep_> ())
{
}
#endif
<commit_msg>another missed override<commit_after>/*
 * Copyright(c) Sophist Solutions, Inc. 1990-2017.  All rights reserved
 */
#include "../../../StroikaPreComp.h"

#include "../../../Characters/Format.h"

#include "Reader.h"

//// SEEE http://www.zlib.net/zlib_how.html
/// THIS SHOWS PRETTY SIMPLE EXAMPLE OF HOW TO DO COMPRESS/DECOMPRESS AND WE CAN USE THAT to amke new stream object
/// where inner loop is done each time through with a CHUNK

#if qHasFeature_ZLib
#include <zlib.h>

#if defined(_MSC_VER)
// Use #pragma comment lib instead of explicit entry in the lib entry of the project file
#pragma comment(lib, "zlib.lib")
#endif

using namespace Stroika::Foundation;
using namespace Stroika::Foundation::DataExchange;
using namespace Stroika::Foundation::DataExchange::Compression;
using namespace Stroika::Foundation::Streams;

// Comment this in to turn on aggressive noisy DbgTrace in this module
//#define   USE_NOISY_TRACE_IN_THIS_MODULE_       1

namespace {

    void ThrowIfZLibErr_ (int err)
    {
        // VERY ROUGH DRAFT - probably need a more specific exception object type
        if (err != Z_OK) {
            switch (err) {
                case Z_VERSION_ERROR:
                    Execution::Throw (Execution::StringException (L"ZLIB Z_VERSION_ERROR"));
                case Z_DATA_ERROR:
                    Execution::Throw (Execution::StringException (L"ZLIB Z_DATA_ERROR"));
                case Z_ERRNO:
                    Execution::Throw (Execution::StringException (Characters::Format (L"ZLIB Z_ERRNO (errno=%d", errno)));
                default:
                    Execution::Throw (Execution::StringException (Characters::Format (L"ZLIB ERR %d", err)));
            }
        }
    }

    using Memory::Byte;
    struct MyCompressionStream_ : InputStream<Byte>::Ptr {
        struct BaseRep_ : public InputStream<Byte>::_IRep {
            static constexpr size_t                 CHUNK = 16384;
            Streams::InputStream<Memory::Byte>::Ptr fInStream_;
            z_stream                                fZStream_;
            Byte                                    fInBuf_[CHUNK];
            SeekOffsetType                          _fSeekOffset{};
            BaseRep_ (const Streams::InputStream<Memory::Byte>::Ptr& in)
                : fInStream_ (in)
                , fZStream_{}
            {
            }
            virtual ~BaseRep_ () = default;
            virtual bool IsSeekable () const override
            {
                // for now - KISS
                return false; // SHOULD allow seekable IFF src is seekable
            }
            virtual void CloseRead () override
            {
                Require (IsOpenRead ());
                fInStream_.Close ();
                Assert (fInStream_ == nullptr);
                Ensure (not IsOpenRead ());
            }
            virtual bool IsOpenRead () const override
            {
                return fInStream_ != nullptr;
            }
            virtual SeekOffsetType GetReadOffset () const override
            {
                return _fSeekOffset;
            }
            virtual SeekOffsetType SeekRead (Whence whence, SignedSeekOffsetType offset) override
            {
                RequireNotReached ();
                return SeekOffsetType{};
            }
            nonvirtual bool _AssureInputAvailableReturnTrueIfAtEOF ()
            {
                if (fZStream_.avail_in == 0) {
                    Assert (NEltsOf (fInBuf_) < numeric_limits<uInt>::max ());
                    fZStream_.avail_in = static_cast<uInt> (fInStream_.Read (begin (fInBuf_), end (fInBuf_)));
                    fZStream_.next_in  = begin (fInBuf_);
                }
                return fZStream_.avail_in == 0;
            }
        };
        struct DeflateRep_ : BaseRep_ {
            DeflateRep_ (const Streams::InputStream<Memory::Byte>::Ptr& in)
                : BaseRep_ (in)
            {
                int level = Z_DEFAULT_COMPRESSION;
                ThrowIfZLibErr_ (::deflateInit (&fZStream_, level));
            }
            virtual ~DeflateRep_ ()
            {
                Verify (::deflateEnd (&fZStream_) == Z_OK);
            }
            virtual size_t Read (ElementType* intoStart, ElementType* intoEnd) override
            {
                Require (intoStart < intoEnd); // API rule for streams
            Again:
                bool isAtSrcEOF = _AssureInputAvailableReturnTrueIfAtEOF ();

                Require (intoStart < intoEnd);
                ptrdiff_t outBufSize = intoEnd - intoStart;

                int flush = isAtSrcEOF ? Z_FINISH : Z_NO_FLUSH;

                fZStream_.avail_out = static_cast<uInt> (outBufSize);
                fZStream_.next_out  = intoStart;
                int ret;
                switch (ret = ::deflate (&fZStream_, flush)) {
                    case Z_OK:
                        break;
                    case Z_STREAM_END:
                        break;
                    default:
                        ThrowIfZLibErr_ (ret);
                }

                ptrdiff_t pulledOut = outBufSize - fZStream_.avail_out;
                Assert (pulledOut <= outBufSize);
                if (pulledOut == 0 and not isAtSrcEOF and flush == Z_NO_FLUSH) {
                    goto Again;
                }
                _fSeekOffset += pulledOut;
                return pulledOut;
            }
            virtual Memory::Optional<size_t> ReadNonBlocking (ElementType* intoStart, ElementType* intoEnd) override
            {
                Require ((intoStart == nullptr and intoEnd == nullptr) or (intoEnd - intoStart) >= 1);
// https://stroika.atlassian.net/browse/STK-567 EXPERIMENTAL DRAFT API - INCOMPLETE IMPL
#if 0
                if (intoStart == nullptr) {
                    // Just check if any data available

                }
                else {
                    Assert (intoStart < intoEnd);
                Again:
                    if (fZStream_.avail_in == 0) {
                        Assert (NEltsOf (fInBuf_) < numeric_limits<uInt>::max ());
                        if (auto o = fInStream_.ReadNonBlocking (begin (fInBuf_), end (fInBuf_))) {
                            fZStream_.avail_in = static_cast<uInt> (*o);
                            fZStream_.next_in = begin (fInBuf_);
                        }
                        else {
                            return {};
                        }
                    }
                    ptrdiff_t outBufSize = intoEnd - intoStart;
                    fZStream_.avail_out = static_cast<uInt> (outBufSize);
                    fZStream_.next_out = intoStart;
                    bool isAtSrcEOF = fZStream_.avail_in == 0;
                    int flush = isAtSrcEOF ? Z_FINISH : Z_NO_FLUSH;
                    int ret;
                    switch (ret = ::deflate (&fZStream_, flush)) {
                    case Z_OK:
                        break;
                    case Z_STREAM_END:
                        break;
                    default:
                        ThrowIfZLibErr_ (ret);
                    }
                    ptrdiff_t pulledOut = outBufSize - fZStream_.avail_out;
                    Assert (pulledOut <= outBufSize);
                    if (pulledOut == 0 and not isAtSrcEOF) {
                        goto Again;
                    }
                    _fSeekOffset += pulledOut;
                    return pulledOut;
                }
#else
                // INCOMPLETE - tricky... most common cases easy, but edges hard...
                if (fZStream_.avail_out == 0) {
                    if (fZStream_.avail_in == 0) {
                        if (Memory::Optional<size_t> tmpAvail = fInStream_.ReadNonBlocking (begin (fInBuf_), end (fInBuf_))) {
                        }
                        else {
                            return {};
                        }
                    }
                }
#endif
                WeakAssert (false);
                // @todo - FIX TO REALLY CHECK
                return {};
            }
        };
        struct InflateRep_ : BaseRep_ {
            InflateRep_ (const Streams::InputStream<Memory::Byte>::Ptr& in)
                : BaseRep_ (in)
            {
                // see http://zlib.net/manual.html  for meaning of params and http://www.lemoda.net/c/zlib-open-read/ for example
                constexpr int windowBits       = 15;
                constexpr int ENABLE_ZLIB_GZIP = 32;
                ThrowIfZLibErr_ (::inflateInit2 (&fZStream_, windowBits | ENABLE_ZLIB_GZIP));
            }
            virtual ~InflateRep_ ()
            {
                Verify (::inflateEnd (&fZStream_) == Z_OK);
            }
            virtual size_t Read (ElementType* intoStart, ElementType* intoEnd) override
            {
                Require (intoStart < intoEnd); // API rule for streams
            Again:
                bool      isAtSrcEOF = _AssureInputAvailableReturnTrueIfAtEOF ();
                ptrdiff_t outBufSize = intoEnd - intoStart;

                fZStream_.avail_out = static_cast<uInt> (outBufSize);
                fZStream_.next_out  = intoStart;
                int ret;
                switch (ret = ::inflate (&fZStream_, Z_NO_FLUSH)) {
                    case Z_OK:
                        break;
                    case Z_STREAM_END:
                        break;
                    default:
                        ThrowIfZLibErr_ (ret);
                }

                ptrdiff_t pulledOut = outBufSize - fZStream_.avail_out;
                Assert (pulledOut <= outBufSize);
                if (pulledOut == 0 and not isAtSrcEOF) {
                    goto Again;
                }
                _fSeekOffset += pulledOut;
                return pulledOut;
            }
            virtual Memory::Optional<size_t> ReadNonBlocking (ElementType* intoStart, ElementType* intoEnd) override
            {
                // https://stroika.atlassian.net/browse/STK-567 EXPERIMENTAL DRAFT API - incomplete IMPL
                Require ((intoStart == nullptr and intoEnd == nullptr) or (intoEnd - intoStart) >= 1);
                WeakAssert (false);
                // @todo - FIX TO REALLY CHECK
                return {};
            }
        };
        enum Compression { eCompression };
        enum DeCompression { eDeCompression };
        MyCompressionStream_ (Compression, const Streams::InputStream<Memory::Byte>::Ptr& in)
            : InputStream<Byte>::Ptr (make_shared<DeflateRep_> (in))
        {
        }
        MyCompressionStream_ (DeCompression, const Streams::InputStream<Memory::Byte>::Ptr& in)
            : InputStream<Byte>::Ptr (make_shared<InflateRep_> (in))
        {
        }
    };
}
#endif

#if qHasFeature_ZLib
class Zip::Reader::Rep_ : public Reader::_IRep {
public:
    virtual InputStream<Byte>::Ptr Compress (const InputStream<Byte>::Ptr& src) const override
    {
        return MyCompressionStream_ (MyCompressionStream_::eCompression, src);
    }
    virtual InputStream<Byte>::Ptr Decompress (const InputStream<Byte>::Ptr& src) const override
    {
        return MyCompressionStream_ (MyCompressionStream_::eDeCompression, src);
    }
};

Zip::Reader::Reader ()
    : DataExchange::Compression::Reader (make_shared<Rep_> ())
{
}
#endif
<|endoftext|>


<commit_before>#include "UDPSocket.hpp"

#include "Types.hpp"

#include "Experimental.hpp"
#include "CRC32.hpp"

#include "Debug.hpp"
#include "Log.hpp"

namespace MPACK
{
	namespace Network
	{
		UDPSocket::UDPSocket()
			: isNonBlocking(false), isBroadcasting(false), isCRC32Enabled(false)
		{
			socket=Wrapper::Socket(Protocol::UDP);
		}

		UDPSocket::~UDPSocket()
		{
			Shutdown();
		}

		bool UDPSocket::Bind(int port)
		{
			inAddress.SetAnyAddress();
			inAddress.SetPort(port);

			if(bind(socket, inAddress.GetAddrPointer(), sizeof(sockaddr)) == 0)
			{
				return true;
			}
			return false;
		}

		void UDPSocket::Shutdown()
		{
			Wrapper::CloseSocket(socket);
		}

		int UDPSocket::SetNonBlocking(const bool &mode)
		{
			if(mode==isNonBlocking)
			{
				return 0;
			}
			isNonBlocking = mode;

			u_long set = 1;
			if(!isNonBlocking)
			{
				set = 0;
			}

#ifdef WINDOWS_PLATFORM
			return ioctlsocket(socket, FIONBIO, &set);
#elif	defined(LINUX_PLATFORM)
			return 0;//ioctl(sock, FIONBIO, &set);
#endif
		}

		int UDPSocket::SetBroadcast(const bool &mode)
		{
			if(mode==isBroadcasting)
			{
				return 0;
			}
			isBroadcasting=mode;

			u_long set = 0;
			if(isBroadcasting)
			{
				set = 1;
			}

			return Wrapper::SetBroadcast(socket,set);
		}

		bool UDPSocket::IsNonBlocking() const
		{
			return isNonBlocking;
		}

		bool UDPSocket::IsBroadcasting() const
		{
			return isBroadcasting;
		}

		void UDPSocket::EnableCRC32()
		{
			isCRC32Enabled = true;
		}

		void UDPSocket::DisableCRC32()
		{
			isCRC32Enabled = false;
		}

		bool UDPSocket::IsCRC32Enabled() const
		{
			return isCRC32Enabled;
		}

		bool UDPSocket::Poll(UDPMessage &message)
		{
			int flag=0;
			if(isNonBlocking)
			{
				flag=MSG_DONTWAIT;
			}

			message.Clear();
			int ret=Wrapper::GetPacket(socket, message.data, UDPMSG_MAXBUFFERSIZE, flag, lastContact.GetAddrPointer());
			if(ret>0)
			{
				message.length=ret;

				if(isCRC32Enabled)
				{
					if(message.length <= sizeof(uint32))
					{
						return false;
					}

					uint32 crcValue = 0;
					memcpy(&crcValue, message.data+message.length-sizeof(uint32), sizeof(uint32));

					CRC32 crc;
					crc.Reset();
					crc.AddData(message.data, message.length - sizeof(uint32));
					if(crcValue != crc.Get())
					{
						message.Clear();
						return false;
					}
					else
					{
						message.length=ret - sizeof(uint32);
					}
				}

				return true;
			}
			return false;
		}

		int UDPSocket::SendTo(UDPMessage &message, const SocketAddress &address)
		{
			int flag=0;

			if(message.length == 0)
			{
				return 0;
			}

			if(isNonBlocking)
			{
				flag=MSG_DONTWAIT;
			}

			if(isCRC32Enabled)
			{
				message.data[message.length] = 0;
				CRC32 crc;
				crc.Reset();
				crc.AddData(message.data, message.length);
				uint32 crcValue = crc.Get();
				message.Write((char*)&crcValue, (int)sizeof(crcValue));
			}

			return Wrapper::SendPacket(socket, message.data, message.length, flag, (const sockaddr*)address.GetAddrPointer());
		}
	}
}
<commit_msg>Remove unnecesary crc.reset()<commit_after>#include "UDPSocket.hpp"

#include "Types.hpp"

#include "Experimental.hpp"
#include "CRC32.hpp"

#include "Debug.hpp"
#include "Log.hpp"

namespace MPACK
{
	namespace Network
	{
		UDPSocket::UDPSocket()
			: isNonBlocking(false), isBroadcasting(false), isCRC32Enabled(false)
		{
			socket=Wrapper::Socket(Protocol::UDP);
		}

		UDPSocket::~UDPSocket()
		{
			Shutdown();
		}

		bool UDPSocket::Bind(int port)
		{
			inAddress.SetAnyAddress();
			inAddress.SetPort(port);

			if(bind(socket, inAddress.GetAddrPointer(), sizeof(sockaddr)) == 0)
			{
				return true;
			}
			return false;
		}

		void UDPSocket::Shutdown()
		{
			Wrapper::CloseSocket(socket);
		}

		int UDPSocket::SetNonBlocking(const bool &mode)
		{
			if(mode==isNonBlocking)
			{
				return 0;
			}
			isNonBlocking = mode;

			u_long set = 1;
			if(!isNonBlocking)
			{
				set = 0;
			}

#ifdef WINDOWS_PLATFORM
			return ioctlsocket(socket, FIONBIO, &set);
#elif	defined(LINUX_PLATFORM)
			return 0;//ioctl(sock, FIONBIO, &set);
#endif
		}

		int UDPSocket::SetBroadcast(const bool &mode)
		{
			if(mode==isBroadcasting)
			{
				return 0;
			}
			isBroadcasting=mode;

			u_long set = 0;
			if(isBroadcasting)
			{
				set = 1;
			}

			return Wrapper::SetBroadcast(socket,set);
		}

		bool UDPSocket::IsNonBlocking() const
		{
			return isNonBlocking;
		}

		bool UDPSocket::IsBroadcasting() const
		{
			return isBroadcasting;
		}

		void UDPSocket::EnableCRC32()
		{
			isCRC32Enabled = true;
		}

		void UDPSocket::DisableCRC32()
		{
			isCRC32Enabled = false;
		}

		bool UDPSocket::IsCRC32Enabled() const
		{
			return isCRC32Enabled;
		}

		bool UDPSocket::Poll(UDPMessage &message)
		{
			int flag=0;
			if(isNonBlocking)
			{
				flag=MSG_DONTWAIT;
			}

			message.Clear();
			int ret=Wrapper::GetPacket(socket, message.data, UDPMSG_MAXBUFFERSIZE, flag, lastContact.GetAddrPointer());
			if(ret>0)
			{
				message.length=ret;

				if(isCRC32Enabled)
				{
					if(message.length <= sizeof(uint32))
					{
						return false;
					}

					uint32 crcValue = 0;
					memcpy(&crcValue, message.data+message.length-sizeof(uint32), sizeof(uint32));

					CRC32 crc;
					crc.Reset();
					crc.AddData(message.data, message.length - sizeof(uint32));
					if(crcValue != crc.Get())
					{
						message.Clear();
						return false;
					}
					else
					{
						message.length=ret - sizeof(uint32);
					}
				}

				return true;
			}
			return false;
		}

		int UDPSocket::SendTo(UDPMessage &message, const SocketAddress &address)
		{
			int flag=0;

			if(message.length == 0)
			{
				return 0;
			}

			if(isNonBlocking)
			{
				flag=MSG_DONTWAIT;
			}

			if(isCRC32Enabled)
			{
				message.data[message.length] = 0;
				CRC32 crc;
				crc.AddData(message.data, message.length);
				uint32 crcValue = crc.Get();
				message.Write((char*)&crcValue, (int)sizeof(crcValue));
			}

			return Wrapper::SendPacket(socket, message.data, message.length, flag, (const sockaddr*)address.GetAddrPointer());
		}
	}
}
<|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010-2011 Openismus GmbH.
**   Authors: Peter Penz (ppenz@openismus.com)
**            Patricia Santana Cruz (patriciasantanacruz@gmail.com)
**
** Contact: Nokia Corporation (info@qt.nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at info@qt.nokia.com.
**
**************************************************************************/

#include "makefileparser.h"

#include <utils/qtcassert.h>

#include <QFile>
#include <QDir>
#include <QFileInfoList>
#include <QMutexLocker>

using namespace AutotoolsProjectManager::Internal;

MakefileParser::MakefileParser(const QString &makefile) :
    QObject(),
    m_success(false),
    m_cancel(false),
    m_mutex(),
    m_makefile(makefile),
    m_executable(),
    m_sources(),
    m_makefiles(),
    m_includePaths(),
    m_line(),
    m_textStream()
{
}

MakefileParser::~MakefileParser()
{
    delete m_textStream.device();
}

bool MakefileParser::parse()
{
    m_mutex.lock();
    m_cancel = false;
    m_mutex.unlock(),

    m_success = true;
    m_executable.clear();
    m_sources.clear();
    m_makefiles.clear();

    QFile *file = new QFile(m_makefile);
    if (!file->open(QIODevice::ReadOnly | QIODevice::Text))
        return false;

    QFileInfo info(m_makefile);
    m_makefiles.append(info.fileName());

    emit status(tr("Parsing %1 in directory %2").arg(info.fileName()).arg(info.absolutePath()));

    m_textStream.setDevice(file);

    do {
        m_line = m_textStream.readLine();
        switch (topTarget()) {
        case AmDefaultSourceExt: parseDefaultSourceExtensions(); break;
        case BinPrograms: parseBinPrograms(); break;
        case BuiltSources: break; // TODO: Add to m_sources?
        case Sources: parseSources(); break;
        case SubDirs: parseSubDirs(); break;
        case Undefined:
        default: break;
        }
    } while (!m_line.isNull());

    parseIncludePaths();

    return m_success;
}

QStringList MakefileParser::sources() const
{
    return m_sources;
}

QStringList MakefileParser::makefiles() const
{
    return m_makefiles;
}

QString MakefileParser::executable() const
{
    return m_executable;
}

QStringList MakefileParser::includePaths() const
{
    return m_includePaths;
}

void MakefileParser::cancel()
{
    QMutexLocker locker(&m_mutex);
    m_cancel = true;
}

bool MakefileParser::isCanceled() const
{
    QMutexLocker locker(&m_mutex);
    return m_cancel;
}

MakefileParser::TopTarget MakefileParser::topTarget() const
{
    TopTarget topTarget = Undefined;

    const QString line = m_line.simplified();
    if (!line.isEmpty() && !line.startsWith(QLatin1Char('#'))) {
        // TODO: Check how many fixed strings like AM_DEFAULT_SOURCE_EXT will
        // be needed vs. variable strings like _SOURCES. Dependent on this a
        // more clever way than this (expensive) if-cascading might be done.
        if (line.startsWith(QLatin1String("AM_DEFAULT_SOURCE_EXT =")))
            topTarget = AmDefaultSourceExt;
        else if (line.startsWith(QLatin1String("bin_PROGRAMS =")))
            topTarget = BinPrograms;
        else if (line.startsWith(QLatin1String("BUILT_SOURCES =")))
            topTarget = BuiltSources;
        else if (line.contains(QLatin1String("SUBDIRS =")))
            topTarget = SubDirs;
        else if (line.contains(QLatin1String("_SOURCES =")))
            topTarget = Sources;
    }

    return topTarget;
}

void MakefileParser::parseBinPrograms()
{
    QTC_ASSERT(m_line.contains(QLatin1String("bin_PROGRAMS")), return);
    const QStringList binPrograms = targetValues();

    // TODO: are multiple values possible?
    if (binPrograms.size() == 1) {
        QFileInfo info(binPrograms.first());
        m_executable = info.fileName();
    }
}

void MakefileParser::parseSources()
{
    QTC_ASSERT(m_line.contains(QLatin1String("_SOURCES")), return);

    bool hasVariables = false;
    m_sources.append(targetValues(&hasVariables));

    // Skip parsing of Makefile.am for getting the sub directories,
    // as variables have been used. As fallback all sources will be added.
    if (hasVariables)
        addAllSources();

    // Duplicates might be possible in combination with 'AM_DEFAULT_SOURCE_EXT ='
    m_sources.removeDuplicates();

    // TODO: Definitions like "SOURCES = ../src.cpp" are ignored currently.
    // This case must be handled correctly in MakefileParser::parseSubDirs(),
    // where the current sub directory must be shortened.
    QStringList::iterator it = m_sources.begin();
    while (it != m_sources.end()) {
        if ((*it).startsWith(QLatin1String("..")))
            it = m_sources.erase(it);
        else
            ++it;
    }
}

void MakefileParser::parseDefaultSourceExtensions()
{
    QTC_ASSERT(m_line.contains(QLatin1String("AM_DEFAULT_SOURCE_EXT")), return);
    const QStringList extensions = targetValues();
    if (extensions.isEmpty()) {
        m_success = false;
        return;
    }

    QFileInfo info(m_makefile);
    const QString dirName = info.absolutePath();
    m_sources.append(directorySources(dirName, extensions));

    // Duplicates might be possible in combination with '_SOURCES ='
    m_sources.removeDuplicates();
}

void MakefileParser::parseSubDirs()
{
    QTC_ASSERT(m_line.contains(QLatin1String("SUBDIRS")), return);
    if (isCanceled()) {
        m_success = false;
        return;
    }

    QFileInfo info(m_makefile);
    const QString path = info.absolutePath();
    const QString makefileName = info.fileName();

    bool hasVariables = false;
    QStringList subDirs = targetValues(&hasVariables);
    if (hasVariables) {
        // Skip parsing of Makefile.am for getting the sub directories,
        // as variables have been used. As fallback all sources will be added.
        addAllSources();
        return;
    }

    // If the SUBDIRS values contain a '.' or a variable like $(test),
    // all the sub directories of the current folder must get parsed.
    bool hasDotSubDir = false;
    QStringList::iterator it = subDirs.begin();
    while (it != subDirs.end()) {
        // Erase all entries that represent a '.'
        if ((*it) == QLatin1String(".")) {
            hasDotSubDir = true;
            it = subDirs.erase(it);
        } else {
            ++it;
        }
    }
    if (hasDotSubDir) {
        // Add all sub directories of the current folder
        QDir dir(path);
        dir.setFilter(QDir::Dirs | QDir::NoDotAndDotDot);
        foreach (const QFileInfo& info, dir.entryInfoList()) {
            subDirs.append(info.fileName());
        }
    }
    subDirs.removeDuplicates();

    // Delegate the parsing of all sub directories to a local
    // makefile parser and merge the results
    foreach (const QString& subDir, subDirs) {
        const QChar slash = QLatin1Char('/');
        const QString subDirMakefile = path + slash + subDir
                                       + slash + makefileName;

        // Parse sub directory
        QFile file(subDirMakefile);

        // Don't try to parse a file, that might not exist (e. g.
        // if SUBDIRS specifies a 'po' directory).
        if (!file.exists())
            continue;

        MakefileParser parser(subDirMakefile);
        connect(&parser, SIGNAL(status(QString)), this, SIGNAL(status(QString)));
        const bool success = parser.parse();

        // Don't return, try to parse as many sub directories
        // as possible
        if (!success)
            m_success = false;

        m_makefiles.append(subDir + slash + makefileName);

        // Append the sources of the sub directory to the
        // current sources
        foreach (const QString& source, parser.sources())
            m_sources.append(subDir + slash + source);

        // Duplicates might be possible in combination with several
        // "..._SUBDIRS" targets
        m_makefiles.removeDuplicates();
        m_sources.removeDuplicates();
    }

    if (subDirs.isEmpty())
        m_success = false;
}

QStringList MakefileParser::directorySources(const QString &directory,
                                             const QStringList &extensions)
{
    if (isCanceled()) {
        m_success = false;
        return QStringList();
    }

    emit status(tr("Parsing directory %1").arg(directory));

    QStringList list; // return value

    QDir dir(directory);
    dir.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);

    const QFileInfoList infos = dir.entryInfoList();
    foreach (const QFileInfo& info, infos) {
        if (info.isDir()) {
            // Append recursively sources from the sub directory
            const QStringList subDirSources = directorySources(info.absoluteFilePath(),
                                                               extensions);
            const QString dirPath = info.fileName();
            foreach (const QString& subDirSource, subDirSources)
                list.append(dirPath + QLatin1Char('/') + subDirSource);
        } else {
            // Check whether the file matches to an extension
            foreach (const QString& extension, extensions) {
                if (info.fileName().endsWith(extension)) {
                    list.append(info.fileName());
                    appendHeader(list, dir, info.baseName());
                    break;
                }
            }
        }
    }

    return list;
}

QStringList MakefileParser::targetValues(bool *hasVariables)
{
    QStringList values;
    if (hasVariables != 0)
        *hasVariables = false;

    const int index = m_line.indexOf(QLatin1Char('='));
    if (index < 0) {
        m_success = false;
        return QStringList();
    }

    m_line.remove(0, index + 1); // remove the 'target = ' prefix

    bool endReached = false;
    do {
        m_line = m_line.simplified();

        // Get all values of a line separated by spaces.
        // Values representing a variable like $(value) get
        // removed currently.
        QStringList lineValues = m_line.split(QLatin1Char(' '));
        QStringList::iterator it = lineValues.begin();
        while (it != lineValues.end()) {
            if ((*it).startsWith(QLatin1String("$("))) {
                it = lineValues.erase(it);
                if (hasVariables != 0)
                    *hasVariables = true;
            } else {
                ++it;
            }
        }

        endReached = lineValues.isEmpty();
        if (!endReached) {
            const QChar backSlash = QLatin1Char('\\');
            QString last = lineValues.last();
            if (last.endsWith(backSlash)) {
                // The last value contains a backslash. Remove the
                // backslash and replace the last value.
                lineValues.pop_back();
                last.remove(backSlash);
                if (!last.isEmpty())
                    lineValues.push_back(last);

                values.append(lineValues);
                m_line = m_textStream.readLine();
                endReached = m_line.isNull();
            } else {
                values.append(lineValues);
                endReached = true;
            }
        }
    } while (!endReached);

    return values;
}

void MakefileParser::appendHeader(QStringList &list,  const QDir &dir, const QString &fileName)
{
    const char *const headerExtensions[] = { ".h", ".hh", ".hg", ".hxx", ".hpp", 0 };
    int i = 0;
    while (headerExtensions[i] != 0) {
        const QString headerFile = fileName + QLatin1String(headerExtensions[i]);
        QFileInfo fileInfo(dir, headerFile);
        if (fileInfo.exists())
            list.append(headerFile);
        ++i;
    }
}

void MakefileParser::addAllSources()
{
    QStringList extensions;
    extensions << QLatin1String(".c")
               << QLatin1String(".cpp")
               << QLatin1String(".cc")
               << QLatin1String(".cxx")
               << QLatin1String(".ccg");
    QFileInfo info(m_makefile);
    m_sources.append(directorySources(info.absolutePath(), extensions));
    m_sources.removeDuplicates();
}

void MakefileParser::parseIncludePaths()
{
    QFileInfo info(m_makefile);
    const QString dirName = info.absolutePath();

    QFile file(dirName + QLatin1String("/Makefile"));
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
        return;

    // TODO: The parsing is done very poor. Comments are ignored and targets
    // are ignored too. Whether it is worth to improve this, depends on whether
    // we want to parse the generated Makefile at all or whether we want to
    // improve the Makefile.am parsing to be aware of variables.
    QTextStream textStream(&file);
    QString line;
    do {
        line = textStream.readLine();
        QStringList terms = line.split(QLatin1Char(' '), QString::SkipEmptyParts);
        foreach (const QString &term, terms) {
            if (term.startsWith(QLatin1String("-I"))) {
                QString includePath = term.right(term.length() - 2); // remove the "-I"
                if (includePath == QLatin1String("."))
                    includePath = dirName;
                if (!includePath.isEmpty())
                    m_includePaths += includePath;
            }
        }
    } while (!line.isNull());

    m_includePaths.removeDuplicates();
}
<commit_msg>autotools: Skip empty parts in target lists<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010-2011 Openismus GmbH.
**   Authors: Peter Penz (ppenz@openismus.com)
**            Patricia Santana Cruz (patriciasantanacruz@gmail.com)
**
** Contact: Nokia Corporation (info@qt.nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at info@qt.nokia.com.
**
**************************************************************************/

#include "makefileparser.h"

#include <utils/qtcassert.h>

#include <QFile>
#include <QDir>
#include <QFileInfoList>
#include <QMutexLocker>

using namespace AutotoolsProjectManager::Internal;

MakefileParser::MakefileParser(const QString &makefile) :
    QObject(),
    m_success(false),
    m_cancel(false),
    m_mutex(),
    m_makefile(makefile),
    m_executable(),
    m_sources(),
    m_makefiles(),
    m_includePaths(),
    m_line(),
    m_textStream()
{
}

MakefileParser::~MakefileParser()
{
    delete m_textStream.device();
}

bool MakefileParser::parse()
{
    m_mutex.lock();
    m_cancel = false;
    m_mutex.unlock(),

    m_success = true;
    m_executable.clear();
    m_sources.clear();
    m_makefiles.clear();

    QFile *file = new QFile(m_makefile);
    if (!file->open(QIODevice::ReadOnly | QIODevice::Text))
        return false;

    QFileInfo info(m_makefile);
    m_makefiles.append(info.fileName());

    emit status(tr("Parsing %1 in directory %2").arg(info.fileName()).arg(info.absolutePath()));

    m_textStream.setDevice(file);

    do {
        m_line = m_textStream.readLine();
        switch (topTarget()) {
        case AmDefaultSourceExt: parseDefaultSourceExtensions(); break;
        case BinPrograms: parseBinPrograms(); break;
        case BuiltSources: break; // TODO: Add to m_sources?
        case Sources: parseSources(); break;
        case SubDirs: parseSubDirs(); break;
        case Undefined:
        default: break;
        }
    } while (!m_line.isNull());

    parseIncludePaths();

    return m_success;
}

QStringList MakefileParser::sources() const
{
    return m_sources;
}

QStringList MakefileParser::makefiles() const
{
    return m_makefiles;
}

QString MakefileParser::executable() const
{
    return m_executable;
}

QStringList MakefileParser::includePaths() const
{
    return m_includePaths;
}

void MakefileParser::cancel()
{
    QMutexLocker locker(&m_mutex);
    m_cancel = true;
}

bool MakefileParser::isCanceled() const
{
    QMutexLocker locker(&m_mutex);
    return m_cancel;
}

MakefileParser::TopTarget MakefileParser::topTarget() const
{
    TopTarget topTarget = Undefined;

    const QString line = m_line.simplified();
    if (!line.isEmpty() && !line.startsWith(QLatin1Char('#'))) {
        // TODO: Check how many fixed strings like AM_DEFAULT_SOURCE_EXT will
        // be needed vs. variable strings like _SOURCES. Dependent on this a
        // more clever way than this (expensive) if-cascading might be done.
        if (line.startsWith(QLatin1String("AM_DEFAULT_SOURCE_EXT =")))
            topTarget = AmDefaultSourceExt;
        else if (line.startsWith(QLatin1String("bin_PROGRAMS =")))
            topTarget = BinPrograms;
        else if (line.startsWith(QLatin1String("BUILT_SOURCES =")))
            topTarget = BuiltSources;
        else if (line.contains(QLatin1String("SUBDIRS =")))
            topTarget = SubDirs;
        else if (line.contains(QLatin1String("_SOURCES =")))
            topTarget = Sources;
    }

    return topTarget;
}

void MakefileParser::parseBinPrograms()
{
    QTC_ASSERT(m_line.contains(QLatin1String("bin_PROGRAMS")), return);
    const QStringList binPrograms = targetValues();

    // TODO: are multiple values possible?
    if (binPrograms.size() == 1) {
        QFileInfo info(binPrograms.first());
        m_executable = info.fileName();
    }
}

void MakefileParser::parseSources()
{
    QTC_ASSERT(m_line.contains(QLatin1String("_SOURCES")), return);

    bool hasVariables = false;
    m_sources.append(targetValues(&hasVariables));

    // Skip parsing of Makefile.am for getting the sub directories,
    // as variables have been used. As fallback all sources will be added.
    if (hasVariables)
        addAllSources();

    // Duplicates might be possible in combination with 'AM_DEFAULT_SOURCE_EXT ='
    m_sources.removeDuplicates();

    // TODO: Definitions like "SOURCES = ../src.cpp" are ignored currently.
    // This case must be handled correctly in MakefileParser::parseSubDirs(),
    // where the current sub directory must be shortened.
    QStringList::iterator it = m_sources.begin();
    while (it != m_sources.end()) {
        if ((*it).startsWith(QLatin1String("..")))
            it = m_sources.erase(it);
        else
            ++it;
    }
}

void MakefileParser::parseDefaultSourceExtensions()
{
    QTC_ASSERT(m_line.contains(QLatin1String("AM_DEFAULT_SOURCE_EXT")), return);
    const QStringList extensions = targetValues();
    if (extensions.isEmpty()) {
        m_success = false;
        return;
    }

    QFileInfo info(m_makefile);
    const QString dirName = info.absolutePath();
    m_sources.append(directorySources(dirName, extensions));

    // Duplicates might be possible in combination with '_SOURCES ='
    m_sources.removeDuplicates();
}

void MakefileParser::parseSubDirs()
{
    QTC_ASSERT(m_line.contains(QLatin1String("SUBDIRS")), return);
    if (isCanceled()) {
        m_success = false;
        return;
    }

    QFileInfo info(m_makefile);
    const QString path = info.absolutePath();
    const QString makefileName = info.fileName();

    bool hasVariables = false;
    QStringList subDirs = targetValues(&hasVariables);
    if (hasVariables) {
        // Skip parsing of Makefile.am for getting the sub directories,
        // as variables have been used. As fallback all sources will be added.
        addAllSources();
        return;
    }

    // If the SUBDIRS values contain a '.' or a variable like $(test),
    // all the sub directories of the current folder must get parsed.
    bool hasDotSubDir = false;
    QStringList::iterator it = subDirs.begin();
    while (it != subDirs.end()) {
        // Erase all entries that represent a '.'
        if ((*it) == QLatin1String(".")) {
            hasDotSubDir = true;
            it = subDirs.erase(it);
        } else {
            ++it;
        }
    }
    if (hasDotSubDir) {
        // Add all sub directories of the current folder
        QDir dir(path);
        dir.setFilter(QDir::Dirs | QDir::NoDotAndDotDot);
        foreach (const QFileInfo& info, dir.entryInfoList()) {
            subDirs.append(info.fileName());
        }
    }
    subDirs.removeDuplicates();

    // Delegate the parsing of all sub directories to a local
    // makefile parser and merge the results
    foreach (const QString& subDir, subDirs) {
        const QChar slash = QLatin1Char('/');
        const QString subDirMakefile = path + slash + subDir
                                       + slash + makefileName;

        // Parse sub directory
        QFile file(subDirMakefile);

        // Don't try to parse a file, that might not exist (e. g.
        // if SUBDIRS specifies a 'po' directory).
        if (!file.exists())
            continue;

        MakefileParser parser(subDirMakefile);
        connect(&parser, SIGNAL(status(QString)), this, SIGNAL(status(QString)));
        const bool success = parser.parse();

        // Don't return, try to parse as many sub directories
        // as possible
        if (!success)
            m_success = false;

        m_makefiles.append(subDir + slash + makefileName);

        // Append the sources of the sub directory to the
        // current sources
        foreach (const QString& source, parser.sources())
            m_sources.append(subDir + slash + source);

        // Duplicates might be possible in combination with several
        // "..._SUBDIRS" targets
        m_makefiles.removeDuplicates();
        m_sources.removeDuplicates();
    }

    if (subDirs.isEmpty())
        m_success = false;
}

QStringList MakefileParser::directorySources(const QString &directory,
                                             const QStringList &extensions)
{
    if (isCanceled()) {
        m_success = false;
        return QStringList();
    }

    emit status(tr("Parsing directory %1").arg(directory));

    QStringList list; // return value

    QDir dir(directory);
    dir.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);

    const QFileInfoList infos = dir.entryInfoList();
    foreach (const QFileInfo& info, infos) {
        if (info.isDir()) {
            // Append recursively sources from the sub directory
            const QStringList subDirSources = directorySources(info.absoluteFilePath(),
                                                               extensions);
            const QString dirPath = info.fileName();
            foreach (const QString& subDirSource, subDirSources)
                list.append(dirPath + QLatin1Char('/') + subDirSource);
        } else {
            // Check whether the file matches to an extension
            foreach (const QString& extension, extensions) {
                if (info.fileName().endsWith(extension)) {
                    list.append(info.fileName());
                    appendHeader(list, dir, info.baseName());
                    break;
                }
            }
        }
    }

    return list;
}

QStringList MakefileParser::targetValues(bool *hasVariables)
{
    QStringList values;
    if (hasVariables != 0)
        *hasVariables = false;

    const int index = m_line.indexOf(QLatin1Char('='));
    if (index < 0) {
        m_success = false;
        return QStringList();
    }

    m_line.remove(0, index + 1); // remove the 'target = ' prefix

    bool endReached = false;
    do {
        m_line = m_line.simplified();

        // Get all values of a line separated by spaces.
        // Values representing a variable like $(value) get
        // removed currently.
        QStringList lineValues = m_line.split(QLatin1Char(' '), QString::SkipEmptyParts);
        QStringList::iterator it = lineValues.begin();
        while (it != lineValues.end()) {
            if ((*it).startsWith(QLatin1String("$("))) {
                it = lineValues.erase(it);
                if (hasVariables != 0)
                    *hasVariables = true;
            } else {
                ++it;
            }
        }

        endReached = lineValues.isEmpty();
        if (!endReached) {
            const QChar backSlash = QLatin1Char('\\');
            QString last = lineValues.last();
            if (last.endsWith(backSlash)) {
                // The last value contains a backslash. Remove the
                // backslash and replace the last value.
                lineValues.pop_back();
                last.remove(backSlash);
                if (!last.isEmpty())
                    lineValues.push_back(last);

                values.append(lineValues);
                m_line = m_textStream.readLine();
                endReached = m_line.isNull();
            } else {
                values.append(lineValues);
                endReached = true;
            }
        }
    } while (!endReached);

    return values;
}

void MakefileParser::appendHeader(QStringList &list,  const QDir &dir, const QString &fileName)
{
    const char *const headerExtensions[] = { ".h", ".hh", ".hg", ".hxx", ".hpp", 0 };
    int i = 0;
    while (headerExtensions[i] != 0) {
        const QString headerFile = fileName + QLatin1String(headerExtensions[i]);
        QFileInfo fileInfo(dir, headerFile);
        if (fileInfo.exists())
            list.append(headerFile);
        ++i;
    }
}

void MakefileParser::addAllSources()
{
    QStringList extensions;
    extensions << QLatin1String(".c")
               << QLatin1String(".cpp")
               << QLatin1String(".cc")
               << QLatin1String(".cxx")
               << QLatin1String(".ccg");
    QFileInfo info(m_makefile);
    m_sources.append(directorySources(info.absolutePath(), extensions));
    m_sources.removeDuplicates();
}

void MakefileParser::parseIncludePaths()
{
    QFileInfo info(m_makefile);
    const QString dirName = info.absolutePath();

    QFile file(dirName + QLatin1String("/Makefile"));
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
        return;

    // TODO: The parsing is done very poor. Comments are ignored and targets
    // are ignored too. Whether it is worth to improve this, depends on whether
    // we want to parse the generated Makefile at all or whether we want to
    // improve the Makefile.am parsing to be aware of variables.
    QTextStream textStream(&file);
    QString line;
    do {
        line = textStream.readLine();
        QStringList terms = line.split(QLatin1Char(' '), QString::SkipEmptyParts);
        foreach (const QString &term, terms) {
            if (term.startsWith(QLatin1String("-I"))) {
                QString includePath = term.right(term.length() - 2); // remove the "-I"
                if (includePath == QLatin1String("."))
                    includePath = dirName;
                if (!includePath.isEmpty())
                    m_includePaths += includePath;
            }
        }
    } while (!line.isNull());

    m_includePaths.removeDuplicates();
}
<|endoftext|>