chore: CRLF to LF

This commit is contained in:
smpn2
2022-12-16 23:18:35 +09:00
parent b7a60638a4
commit 6c914266d9
725 changed files with 131020 additions and 131020 deletions
File diff suppressed because it is too large Load Diff
+134 -134
View File
@@ -1,134 +1,134 @@
/** @file GuillotineBinPack.h
@author Jukka Jylänki
@brief Implements different bin packer algorithms that use the GUILLOTINE data structure.
This work is released to Public Domain, do whatever you want with it.
*/
#pragma once
#include <vector>
#include "Rect.h"
namespace rbp {
/** GuillotineBinPack implements different variants of bin packer algorithms that use the GUILLOTINE data structure
to keep track of the free space of the bin where rectangles may be placed. */
class GuillotineBinPack
{
public:
/// The initial bin size will be (0,0). Call Init to set the bin size.
GuillotineBinPack();
/// Initializes a new bin of the given size.
GuillotineBinPack(int width, int height);
/// (Re)initializes the packer to an empty bin of width x height units. Call whenever
/// you need to restart with a new bin.
void Init(int width, int height);
/// Specifies the different choice heuristics that can be used when deciding which of the free subrectangles
/// to place the to-be-packed rectangle into.
enum FreeRectChoiceHeuristic
{
RectBestAreaFit, ///< -BAF
RectBestShortSideFit, ///< -BSSF
RectBestLongSideFit, ///< -BLSF
RectWorstAreaFit, ///< -WAF
RectWorstShortSideFit, ///< -WSSF
RectWorstLongSideFit ///< -WLSF
};
/// Specifies the different choice heuristics that can be used when the packer needs to decide whether to
/// subdivide the remaining free space in horizontal or vertical direction.
enum GuillotineSplitHeuristic
{
SplitShorterLeftoverAxis, ///< -SLAS
SplitLongerLeftoverAxis, ///< -LLAS
SplitMinimizeArea, ///< -MINAS, Try to make a single big rectangle at the expense of making the other small.
SplitMaximizeArea, ///< -MAXAS, Try to make both remaining rectangles as even-sized as possible.
SplitShorterAxis, ///< -SAS
SplitLongerAxis ///< -LAS
};
/// Inserts a single rectangle into the bin. The packer might rotate the rectangle, in which case the returned
/// struct will have the width and height values swapped.
/// @param merge If true, performs free Rectangle Merge procedure after packing the new rectangle. This procedure
/// tries to defragment the list of disjoint free rectangles to improve packing performance, but also takes up
/// some extra time.
/// @param rectChoice The free rectangle choice heuristic rule to use.
/// @param splitMethod The free rectangle split heuristic rule to use.
Rect Insert(int width, int height, bool merge, FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod);
/// Inserts a list of rectangles into the bin.
/// @param rects The list of rectangles to add. This list will be destroyed in the packing process.
/// @param merge If true, performs Rectangle Merge operations during the packing process.
/// @param rectChoice The free rectangle choice heuristic rule to use.
/// @param splitMethod The free rectangle split heuristic rule to use.
void Insert(std::vector<RectSize> &rects, bool merge,
FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod);
// Implements GUILLOTINE-MAXFITTING, an experimental heuristic that's really cool but didn't quite work in practice.
// void InsertMaxFitting(std::vector<RectSize> &rects, std::vector<Rect> &dst, bool merge,
// FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod);
/// Computes the ratio of used/total surface area. 0.00 means no space is yet used, 1.00 means the whole bin is used.
float Occupancy() const;
/// Returns the internal list of disjoint rectangles that track the free area of the bin. You may alter this vector
/// any way desired, as long as the end result still is a list of disjoint rectangles.
std::vector<Rect> &GetFreeRectangles() { return freeRectangles; }
/// Returns the list of packed rectangles. You may alter this vector at will, for example, you can move a Rect from
/// this list to the Free Rectangles list to free up space on-the-fly, but notice that this causes fragmentation.
std::vector<Rect> &GetUsedRectangles() { return usedRectangles; }
/// Performs a Rectangle Merge operation. This procedure looks for adjacent free rectangles and merges them if they
/// can be represented with a single rectangle. Takes up Theta(|freeRectangles|^2) time.
void MergeFreeList();
private:
int binWidth;
int binHeight;
/// Stores a list of all the rectangles that we have packed so far. This is used only to compute the Occupancy ratio,
/// so if you want to have the packer consume less memory, this can be removed.
std::vector<Rect> usedRectangles;
/// Stores a list of rectangles that represents the free area of the bin. This rectangles in this list are disjoint.
std::vector<Rect> freeRectangles;
#ifdef _DEBUG
/// Used to track that the packer produces proper packings.
DisjointRectCollection disjointRects;
#endif
/// Goes through the list of free rectangles and finds the best one to place a rectangle of given size into.
/// Running time is Theta(|freeRectangles|).
/// @param nodeIndex [out] The index of the free rectangle in the freeRectangles array into which the new
/// rect was placed.
/// @return A Rect structure that represents the placement of the new rect into the best free rectangle.
Rect FindPositionForNewNode(int width, int height, FreeRectChoiceHeuristic rectChoice, int *nodeIndex);
static int ScoreByHeuristic(int width, int height, const Rect &freeRect, FreeRectChoiceHeuristic rectChoice);
// The following functions compute (penalty) score values if a rect of the given size was placed into the
// given free rectangle. In these score values, smaller is better.
static int ScoreBestAreaFit(int width, int height, const Rect &freeRect);
static int ScoreBestShortSideFit(int width, int height, const Rect &freeRect);
static int ScoreBestLongSideFit(int width, int height, const Rect &freeRect);
static int ScoreWorstAreaFit(int width, int height, const Rect &freeRect);
static int ScoreWorstShortSideFit(int width, int height, const Rect &freeRect);
static int ScoreWorstLongSideFit(int width, int height, const Rect &freeRect);
/// Splits the given L-shaped free rectangle into two new free rectangles after placedRect has been placed into it.
/// Determines the split axis by using the given heuristic.
void SplitFreeRectByHeuristic(const Rect &freeRect, const Rect &placedRect, GuillotineSplitHeuristic method);
/// Splits the given L-shaped free rectangle into two new free rectangles along the given fixed split axis.
void SplitFreeRectAlongAxis(const Rect &freeRect, const Rect &placedRect, bool splitHorizontal);
};
}
/** @file GuillotineBinPack.h
@author Jukka Jylänki
@brief Implements different bin packer algorithms that use the GUILLOTINE data structure.
This work is released to Public Domain, do whatever you want with it.
*/
#pragma once
#include <vector>
#include "Rect.h"
namespace rbp {
/** GuillotineBinPack implements different variants of bin packer algorithms that use the GUILLOTINE data structure
to keep track of the free space of the bin where rectangles may be placed. */
class GuillotineBinPack
{
public:
/// The initial bin size will be (0,0). Call Init to set the bin size.
GuillotineBinPack();
/// Initializes a new bin of the given size.
GuillotineBinPack(int width, int height);
/// (Re)initializes the packer to an empty bin of width x height units. Call whenever
/// you need to restart with a new bin.
void Init(int width, int height);
/// Specifies the different choice heuristics that can be used when deciding which of the free subrectangles
/// to place the to-be-packed rectangle into.
enum FreeRectChoiceHeuristic
{
RectBestAreaFit, ///< -BAF
RectBestShortSideFit, ///< -BSSF
RectBestLongSideFit, ///< -BLSF
RectWorstAreaFit, ///< -WAF
RectWorstShortSideFit, ///< -WSSF
RectWorstLongSideFit ///< -WLSF
};
/// Specifies the different choice heuristics that can be used when the packer needs to decide whether to
/// subdivide the remaining free space in horizontal or vertical direction.
enum GuillotineSplitHeuristic
{
SplitShorterLeftoverAxis, ///< -SLAS
SplitLongerLeftoverAxis, ///< -LLAS
SplitMinimizeArea, ///< -MINAS, Try to make a single big rectangle at the expense of making the other small.
SplitMaximizeArea, ///< -MAXAS, Try to make both remaining rectangles as even-sized as possible.
SplitShorterAxis, ///< -SAS
SplitLongerAxis ///< -LAS
};
/// Inserts a single rectangle into the bin. The packer might rotate the rectangle, in which case the returned
/// struct will have the width and height values swapped.
/// @param merge If true, performs free Rectangle Merge procedure after packing the new rectangle. This procedure
/// tries to defragment the list of disjoint free rectangles to improve packing performance, but also takes up
/// some extra time.
/// @param rectChoice The free rectangle choice heuristic rule to use.
/// @param splitMethod The free rectangle split heuristic rule to use.
Rect Insert(int width, int height, bool merge, FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod);
/// Inserts a list of rectangles into the bin.
/// @param rects The list of rectangles to add. This list will be destroyed in the packing process.
/// @param merge If true, performs Rectangle Merge operations during the packing process.
/// @param rectChoice The free rectangle choice heuristic rule to use.
/// @param splitMethod The free rectangle split heuristic rule to use.
void Insert(std::vector<RectSize> &rects, bool merge,
FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod);
// Implements GUILLOTINE-MAXFITTING, an experimental heuristic that's really cool but didn't quite work in practice.
// void InsertMaxFitting(std::vector<RectSize> &rects, std::vector<Rect> &dst, bool merge,
// FreeRectChoiceHeuristic rectChoice, GuillotineSplitHeuristic splitMethod);
/// Computes the ratio of used/total surface area. 0.00 means no space is yet used, 1.00 means the whole bin is used.
float Occupancy() const;
/// Returns the internal list of disjoint rectangles that track the free area of the bin. You may alter this vector
/// any way desired, as long as the end result still is a list of disjoint rectangles.
std::vector<Rect> &GetFreeRectangles() { return freeRectangles; }
/// Returns the list of packed rectangles. You may alter this vector at will, for example, you can move a Rect from
/// this list to the Free Rectangles list to free up space on-the-fly, but notice that this causes fragmentation.
std::vector<Rect> &GetUsedRectangles() { return usedRectangles; }
/// Performs a Rectangle Merge operation. This procedure looks for adjacent free rectangles and merges them if they
/// can be represented with a single rectangle. Takes up Theta(|freeRectangles|^2) time.
void MergeFreeList();
private:
int binWidth;
int binHeight;
/// Stores a list of all the rectangles that we have packed so far. This is used only to compute the Occupancy ratio,
/// so if you want to have the packer consume less memory, this can be removed.
std::vector<Rect> usedRectangles;
/// Stores a list of rectangles that represents the free area of the bin. This rectangles in this list are disjoint.
std::vector<Rect> freeRectangles;
#ifdef _DEBUG
/// Used to track that the packer produces proper packings.
DisjointRectCollection disjointRects;
#endif
/// Goes through the list of free rectangles and finds the best one to place a rectangle of given size into.
/// Running time is Theta(|freeRectangles|).
/// @param nodeIndex [out] The index of the free rectangle in the freeRectangles array into which the new
/// rect was placed.
/// @return A Rect structure that represents the placement of the new rect into the best free rectangle.
Rect FindPositionForNewNode(int width, int height, FreeRectChoiceHeuristic rectChoice, int *nodeIndex);
static int ScoreByHeuristic(int width, int height, const Rect &freeRect, FreeRectChoiceHeuristic rectChoice);
// The following functions compute (penalty) score values if a rect of the given size was placed into the
// given free rectangle. In these score values, smaller is better.
static int ScoreBestAreaFit(int width, int height, const Rect &freeRect);
static int ScoreBestShortSideFit(int width, int height, const Rect &freeRect);
static int ScoreBestLongSideFit(int width, int height, const Rect &freeRect);
static int ScoreWorstAreaFit(int width, int height, const Rect &freeRect);
static int ScoreWorstShortSideFit(int width, int height, const Rect &freeRect);
static int ScoreWorstLongSideFit(int width, int height, const Rect &freeRect);
/// Splits the given L-shaped free rectangle into two new free rectangles after placedRect has been placed into it.
/// Determines the split axis by using the given heuristic.
void SplitFreeRectByHeuristic(const Rect &freeRect, const Rect &placedRect, GuillotineSplitHeuristic method);
/// Splits the given L-shaped free rectangle into two new free rectangles along the given fixed split axis.
void SplitFreeRectAlongAxis(const Rect &freeRect, const Rect &placedRect, bool splitHorizontal);
};
}
+50 -50
View File
@@ -1,51 +1,51 @@
/** @file Rect.cpp
@author Jukka Jylänki
This work is released to Public Domain, do whatever you want with it.
*/
#include <utility>
#include "Rect.h"
namespace rbp {
/*
#include "clb/Algorithm/Sort.h"
int CompareRectShortSide(const Rect &a, const Rect &b)
{
using namespace std;
int smallerSideA = min(a.width, a.height);
int smallerSideB = min(b.width, b.height);
if (smallerSideA != smallerSideB)
return clb::sort::TriCmp(smallerSideA, smallerSideB);
// Tie-break on the larger side.
int largerSideA = max(a.width, a.height);
int largerSideB = max(b.width, b.height);
return clb::sort::TriCmp(largerSideA, largerSideB);
}
*/
/*
int NodeSortCmp(const Rect &a, const Rect &b)
{
if (a.x != b.x)
return clb::sort::TriCmp(a.x, b.x);
if (a.y != b.y)
return clb::sort::TriCmp(a.y, b.y);
if (a.width != b.width)
return clb::sort::TriCmp(a.width, b.width);
return clb::sort::TriCmp(a.height, b.height);
}
*/
bool IsContainedIn(const Rect &a, const Rect &b)
{
return a.x >= b.x && a.y >= b.y
&& a.x+a.width <= b.x+b.width
&& a.y+a.height <= b.y+b.height;
}
/** @file Rect.cpp
@author Jukka Jylänki
This work is released to Public Domain, do whatever you want with it.
*/
#include <utility>
#include "Rect.h"
namespace rbp {
/*
#include "clb/Algorithm/Sort.h"
int CompareRectShortSide(const Rect &a, const Rect &b)
{
using namespace std;
int smallerSideA = min(a.width, a.height);
int smallerSideB = min(b.width, b.height);
if (smallerSideA != smallerSideB)
return clb::sort::TriCmp(smallerSideA, smallerSideB);
// Tie-break on the larger side.
int largerSideA = max(a.width, a.height);
int largerSideB = max(b.width, b.height);
return clb::sort::TriCmp(largerSideA, largerSideB);
}
*/
/*
int NodeSortCmp(const Rect &a, const Rect &b)
{
if (a.x != b.x)
return clb::sort::TriCmp(a.x, b.x);
if (a.y != b.y)
return clb::sort::TriCmp(a.y, b.y);
if (a.width != b.width)
return clb::sort::TriCmp(a.width, b.width);
return clb::sort::TriCmp(a.height, b.height);
}
*/
bool IsContainedIn(const Rect &a, const Rect &b)
{
return a.x >= b.x && a.y >= b.y
&& a.x+a.width <= b.x+b.width
&& a.y+a.height <= b.y+b.height;
}
}
+94 -94
View File
@@ -1,94 +1,94 @@
/** @file Rect.h
@author Jukka Jylänki
This work is released to Public Domain, do whatever you want with it.
*/
#pragma once
#include <vector>
#include <cassert>
#include <cstdlib>
#ifdef _DEBUG
/// debug_assert is an assert that also requires debug mode to be defined.
#define debug_assert(x) assert(x)
#else
#define debug_assert(x)
#endif
//using namespace std;
namespace rbp {
struct RectSize
{
int width;
int height;
};
struct Rect
{
int x;
int y;
int width;
int height;
};
/// Performs a lexicographic compare on (rect short side, rect long side).
/// @return -1 if the smaller side of a is shorter than the smaller side of b, 1 if the other way around.
/// If they are equal, the larger side length is used as a tie-breaker.
/// If the rectangles are of same size, returns 0.
int CompareRectShortSide(const Rect &a, const Rect &b);
/// Performs a lexicographic compare on (x, y, width, height).
int NodeSortCmp(const Rect &a, const Rect &b);
/// Returns true if a is contained in b.
bool IsContainedIn(const Rect &a, const Rect &b);
class DisjointRectCollection
{
public:
std::vector<Rect> rects;
bool Add(const Rect &r)
{
// Degenerate rectangles are ignored.
if (r.width == 0 || r.height == 0)
return true;
if (!Disjoint(r))
return false;
rects.push_back(r);
return true;
}
void Clear()
{
rects.clear();
}
bool Disjoint(const Rect &r) const
{
// Degenerate rectangles are ignored.
if (r.width == 0 || r.height == 0)
return true;
for(size_t i = 0; i < rects.size(); ++i)
if (!Disjoint(rects[i], r))
return false;
return true;
}
static bool Disjoint(const Rect &a, const Rect &b)
{
if (a.x + a.width <= b.x ||
b.x + b.width <= a.x ||
a.y + a.height <= b.y ||
b.y + b.height <= a.y)
return true;
return false;
}
};
}
/** @file Rect.h
@author Jukka Jylänki
This work is released to Public Domain, do whatever you want with it.
*/
#pragma once
#include <vector>
#include <cassert>
#include <cstdlib>
#ifdef _DEBUG
/// debug_assert is an assert that also requires debug mode to be defined.
#define debug_assert(x) assert(x)
#else
#define debug_assert(x)
#endif
//using namespace std;
namespace rbp {
struct RectSize
{
int width;
int height;
};
struct Rect
{
int x;
int y;
int width;
int height;
};
/// Performs a lexicographic compare on (rect short side, rect long side).
/// @return -1 if the smaller side of a is shorter than the smaller side of b, 1 if the other way around.
/// If they are equal, the larger side length is used as a tie-breaker.
/// If the rectangles are of same size, returns 0.
int CompareRectShortSide(const Rect &a, const Rect &b);
/// Performs a lexicographic compare on (x, y, width, height).
int NodeSortCmp(const Rect &a, const Rect &b);
/// Returns true if a is contained in b.
bool IsContainedIn(const Rect &a, const Rect &b);
class DisjointRectCollection
{
public:
std::vector<Rect> rects;
bool Add(const Rect &r)
{
// Degenerate rectangles are ignored.
if (r.width == 0 || r.height == 0)
return true;
if (!Disjoint(r))
return false;
rects.push_back(r);
return true;
}
void Clear()
{
rects.clear();
}
bool Disjoint(const Rect &r) const
{
// Degenerate rectangles are ignored.
if (r.width == 0 || r.height == 0)
return true;
for(size_t i = 0; i < rects.size(); ++i)
if (!Disjoint(rects[i], r))
return false;
return true;
}
static bool Disjoint(const Rect &a, const Rect &b)
{
if (a.x + a.width <= b.x ||
b.x + b.width <= a.x ||
a.y + a.height <= b.y ||
b.y + b.height <= a.y)
return true;
return false;
}
};
}
+2596 -2596
View File
File diff suppressed because it is too large Load Diff
+446 -446
View File
@@ -1,446 +1,446 @@
#ifndef RAPIDXML_PRINT_HPP_INCLUDED
#define RAPIDXML_PRINT_HPP_INCLUDED
// Copyright (C) 2006, 2009 Marcin Kalicinski
// Version 1.13
// Revision $DateTime: 2009/05/13 01:46:17 $
//! \file rapidxml_print.hpp This file contains rapidxml printer implementation
#include "rapidxml.hpp"
// Only include streams if not disabled
#ifndef RAPIDXML_NO_STREAMS
#include <ostream>
#include <iterator>
#endif
namespace rapidxml
{
///////////////////////////////////////////////////////////////////////
// Printing flags
const int print_no_indenting = 0x1; //!< Printer flag instructing the printer to suppress indenting of XML. See print() function.
///////////////////////////////////////////////////////////////////////
// Internal
//! \cond internal
namespace internal
{
///////////////////////////////////////////////////////////////////////////
// Internal character operations
// Copy characters from given range to given output iterator
template<class OutIt, class Ch>
inline OutIt copy_chars(const Ch *begin, const Ch *end, OutIt out)
{
while (begin != end)
*out++ = *begin++;
return out;
}
// Copy characters from given range to given output iterator and expand
// characters into references (&lt; &gt; &apos; &quot; &amp;)
template<class OutIt, class Ch>
inline OutIt copy_and_expand_chars(const Ch *begin, const Ch *end, Ch noexpand, OutIt out)
{
while (begin != end)
{
if (*begin == noexpand)
{
*out++ = *begin; // No expansion, copy character
}
else
{
switch (*begin)
{
case Ch('<'):
*out++ = Ch('&'); *out++ = Ch('l'); *out++ = Ch('t'); *out++ = Ch(';');
break;
case Ch('>'):
*out++ = Ch('&'); *out++ = Ch('g'); *out++ = Ch('t'); *out++ = Ch(';');
break;
case Ch('\''):
*out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('p'); *out++ = Ch('o'); *out++ = Ch('s'); *out++ = Ch(';');
break;
case Ch('"'):
*out++ = Ch('&'); *out++ = Ch('q'); *out++ = Ch('u'); *out++ = Ch('o'); *out++ = Ch('t'); *out++ = Ch(';');
break;
case Ch('&'):
*out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('m'); *out++ = Ch('p'); *out++ = Ch(';');
break;
default:
*out++ = *begin; // No expansion, copy character
}
}
++begin; // Step to next character
}
return out;
}
// Fill given output iterator with repetitions of the same character
template<class OutIt, class Ch>
inline OutIt fill_chars(OutIt out, int n, Ch ch)
{
for (int i = 0; i < n; ++i)
*out++ = ch;
return out;
}
// Find character
template<class Ch, Ch ch>
inline bool find_char(const Ch *begin, const Ch *end)
{
while (begin != end)
if (*begin++ == ch)
return true;
return false;
}
///////////////////////////////////////////////////////////////////////////
// Internal printing operations
template<class OutIt, class Ch>
inline OutIt print_children(OutIt out, const xml_node<Ch> *node, int flags, int indent);
template<class OutIt, class Ch>
inline OutIt print_attributes(OutIt out, const xml_node<Ch> *node, int flags);
template<class OutIt, class Ch>
inline OutIt print_data_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
template<class OutIt, class Ch>
inline OutIt print_cdata_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
template<class OutIt, class Ch>
inline OutIt print_element_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
template<class OutIt, class Ch>
inline OutIt print_declaration_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
template<class OutIt, class Ch>
inline OutIt print_comment_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
template<class OutIt, class Ch>
inline OutIt print_doctype_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
template<class OutIt, class Ch>
inline OutIt print_pi_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
// Print node
template<class OutIt, class Ch>
inline OutIt print_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
{
// Print proper node type
switch (node->type())
{
// Document
case node_document:
out = print_children(out, node, flags, indent);
break;
// Element
case node_element:
out = print_element_node(out, node, flags, indent);
break;
// Data
case node_data:
out = print_data_node(out, node, flags, indent);
break;
// CDATA
case node_cdata:
out = print_cdata_node(out, node, flags, indent);
break;
// Declaration
case node_declaration:
out = print_declaration_node(out, node, flags, indent);
break;
// Comment
case node_comment:
out = print_comment_node(out, node, flags, indent);
break;
// Doctype
case node_doctype:
out = print_doctype_node(out, node, flags, indent);
break;
// Pi
case node_pi:
out = print_pi_node(out, node, flags, indent);
break;
// Unknown
default:
assert(0);
break;
}
// If indenting not disabled, add line break after node
if (!(flags & print_no_indenting))
*out = Ch('\n'), ++out;
// Return modified iterator
return out;
}
// Print children of the node
template<class OutIt, class Ch>
inline OutIt print_children(OutIt out, const xml_node<Ch> *node, int flags, int indent)
{
for (xml_node<Ch> *child = node->first_node(); child; child = child->next_sibling())
out = print_node(out, child, flags, indent);
return out;
}
// Print attributes of the node
template<class OutIt, class Ch>
inline OutIt print_attributes(OutIt out, const xml_node<Ch> *node, int flags)
{
for (xml_attribute<Ch> *attribute = node->first_attribute(); attribute; attribute = attribute->next_attribute())
{
if (attribute->name() && attribute->value())
{
// Print attribute name
*out = Ch(' '), ++out;
out = copy_chars(attribute->name(), attribute->name() + attribute->name_size(), out);
*out = Ch('='), ++out;
// Print attribute value using appropriate quote type
if (find_char<Ch, Ch('"')>(attribute->value(), attribute->value() + attribute->value_size()))
{
*out = Ch('\''), ++out;
out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('"'), out);
*out = Ch('\''), ++out;
}
else
{
*out = Ch('"'), ++out;
out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('\''), out);
*out = Ch('"'), ++out;
}
}
}
return out;
}
// Print data node
template<class OutIt, class Ch>
inline OutIt print_data_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
{
assert(node->type() == node_data);
if (!(flags & print_no_indenting))
out = fill_chars(out, indent, Ch('\t'));
out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
return out;
}
// Print data node
template<class OutIt, class Ch>
inline OutIt print_cdata_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
{
assert(node->type() == node_cdata);
if (!(flags & print_no_indenting))
out = fill_chars(out, indent, Ch('\t'));
*out = Ch('<'); ++out;
*out = Ch('!'); ++out;
*out = Ch('['); ++out;
*out = Ch('C'); ++out;
*out = Ch('D'); ++out;
*out = Ch('A'); ++out;
*out = Ch('T'); ++out;
*out = Ch('A'); ++out;
*out = Ch('['); ++out;
out = copy_chars(node->value(), node->value() + node->value_size(), out);
*out = Ch(']'); ++out;
*out = Ch(']'); ++out;
*out = Ch('>'); ++out;
return out;
}
// Print element node
template<class OutIt, class Ch>
inline OutIt print_element_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
{
assert(node->type() == node_element);
// Print element name and attributes, if any
if (!(flags & print_no_indenting))
out = fill_chars(out, indent, Ch('\t'));
*out = Ch('<'), ++out;
out = copy_chars(node->name(), node->name() + node->name_size(), out);
out = print_attributes(out, node, flags);
// If node is childless
if (node->value_size() == 0 && !node->first_node())
{
// Print childless node tag ending
*out = Ch('/'), ++out;
*out = Ch('>'), ++out;
}
else
{
// Print normal node tag ending
*out = Ch('>'), ++out;
// Test if node contains a single data node only (and no other nodes)
xml_node<Ch> *child = node->first_node();
if (!child)
{
// If node has no children, only print its value without indenting
out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
}
else if (child->next_sibling() == 0 && child->type() == node_data)
{
// If node has a sole data child, only print its value without indenting
out = copy_and_expand_chars(child->value(), child->value() + child->value_size(), Ch(0), out);
}
else
{
// Print all children with full indenting
if (!(flags & print_no_indenting))
*out = Ch('\n'), ++out;
out = print_children(out, node, flags, indent + 1);
if (!(flags & print_no_indenting))
out = fill_chars(out, indent, Ch('\t'));
}
// Print node end
*out = Ch('<'), ++out;
*out = Ch('/'), ++out;
out = copy_chars(node->name(), node->name() + node->name_size(), out);
*out = Ch('>'), ++out;
}
return out;
}
// Print declaration node
template<class OutIt, class Ch>
inline OutIt print_declaration_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
{
// Print declaration start
if (!(flags & print_no_indenting))
out = fill_chars(out, indent, Ch('\t'));
*out = Ch('<'), ++out;
*out = Ch('?'), ++out;
*out = Ch('x'), ++out;
*out = Ch('m'), ++out;
*out = Ch('l'), ++out;
// Print attributes
out = print_attributes(out, node, flags);
// Print declaration end
*out = Ch('?'), ++out;
*out = Ch('>'), ++out;
return out;
}
// Print comment node
template<class OutIt, class Ch>
inline OutIt print_comment_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
{
assert(node->type() == node_comment);
if (!(flags & print_no_indenting))
out = fill_chars(out, indent, Ch('\t'));
*out = Ch('<'), ++out;
*out = Ch('!'), ++out;
*out = Ch('-'), ++out;
*out = Ch('-'), ++out;
out = copy_chars(node->value(), node->value() + node->value_size(), out);
*out = Ch('-'), ++out;
*out = Ch('-'), ++out;
*out = Ch('>'), ++out;
return out;
}
// Print doctype node
template<class OutIt, class Ch>
inline OutIt print_doctype_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
{
assert(node->type() == node_doctype);
if (!(flags & print_no_indenting))
out = fill_chars(out, indent, Ch('\t'));
*out = Ch('<'), ++out;
*out = Ch('!'), ++out;
*out = Ch('D'), ++out;
*out = Ch('O'), ++out;
*out = Ch('C'), ++out;
*out = Ch('T'), ++out;
*out = Ch('Y'), ++out;
*out = Ch('P'), ++out;
*out = Ch('E'), ++out;
*out = Ch(' '), ++out;
out = copy_chars(node->value(), node->value() + node->value_size(), out);
*out = Ch('>'), ++out;
return out;
}
// Print pi node
template<class OutIt, class Ch>
inline OutIt print_pi_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
{
assert(node->type() == node_pi);
if (!(flags & print_no_indenting))
out = fill_chars(out, indent, Ch('\t'));
*out = Ch('<'), ++out;
*out = Ch('?'), ++out;
out = copy_chars(node->name(), node->name() + node->name_size(), out);
*out = Ch(' '), ++out;
out = copy_chars(node->value(), node->value() + node->value_size(), out);
*out = Ch('?'), ++out;
*out = Ch('>'), ++out;
return out;
}
}
//! \endcond
///////////////////////////////////////////////////////////////////////////
// Printing
//! Prints XML to given output iterator.
//! \param out Output iterator to print to.
//! \param node Node to be printed. Pass xml_document to print entire document.
//! \param flags Flags controlling how XML is printed.
//! \return Output iterator pointing to position immediately after last character of printed text.
template<class OutIt, class Ch>
inline OutIt print(OutIt out, const xml_node<Ch> &node, int flags = 0)
{
return internal::print_node(out, &node, flags, 0);
}
#ifndef RAPIDXML_NO_STREAMS
//! Prints XML to given output stream.
//! \param out Output stream to print to.
//! \param node Node to be printed. Pass xml_document to print entire document.
//! \param flags Flags controlling how XML is printed.
//! \return Output stream.
template<class Ch>
inline std::basic_ostream<Ch> &print(std::basic_ostream<Ch> &out, const xml_node<Ch> &node, int flags = 0)
{
print(std::ostream_iterator<Ch>(out), node, flags);
return out;
}
//! Prints formatted XML to given output stream. Uses default printing flags. Use print() function to customize printing process.
//! \param out Output stream to print to.
//! \param node Node to be printed.
//! \return Output stream.
template<class Ch>
inline std::basic_ostream<Ch> &operator <<(std::basic_ostream<Ch> &out, const xml_node<Ch> &node)
{
return print(out, node);
}
#endif
}
#endif
#ifndef RAPIDXML_PRINT_HPP_INCLUDED
#define RAPIDXML_PRINT_HPP_INCLUDED
// Copyright (C) 2006, 2009 Marcin Kalicinski
// Version 1.13
// Revision $DateTime: 2009/05/13 01:46:17 $
//! \file rapidxml_print.hpp This file contains rapidxml printer implementation
#include "rapidxml.hpp"
// Only include streams if not disabled
#ifndef RAPIDXML_NO_STREAMS
#include <ostream>
#include <iterator>
#endif
namespace rapidxml
{
///////////////////////////////////////////////////////////////////////
// Printing flags
const int print_no_indenting = 0x1; //!< Printer flag instructing the printer to suppress indenting of XML. See print() function.
///////////////////////////////////////////////////////////////////////
// Internal
//! \cond internal
namespace internal
{
///////////////////////////////////////////////////////////////////////////
// Internal character operations
// Copy characters from given range to given output iterator
template<class OutIt, class Ch>
inline OutIt copy_chars(const Ch *begin, const Ch *end, OutIt out)
{
while (begin != end)
*out++ = *begin++;
return out;
}
// Copy characters from given range to given output iterator and expand
// characters into references (&lt; &gt; &apos; &quot; &amp;)
template<class OutIt, class Ch>
inline OutIt copy_and_expand_chars(const Ch *begin, const Ch *end, Ch noexpand, OutIt out)
{
while (begin != end)
{
if (*begin == noexpand)
{
*out++ = *begin; // No expansion, copy character
}
else
{
switch (*begin)
{
case Ch('<'):
*out++ = Ch('&'); *out++ = Ch('l'); *out++ = Ch('t'); *out++ = Ch(';');
break;
case Ch('>'):
*out++ = Ch('&'); *out++ = Ch('g'); *out++ = Ch('t'); *out++ = Ch(';');
break;
case Ch('\''):
*out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('p'); *out++ = Ch('o'); *out++ = Ch('s'); *out++ = Ch(';');
break;
case Ch('"'):
*out++ = Ch('&'); *out++ = Ch('q'); *out++ = Ch('u'); *out++ = Ch('o'); *out++ = Ch('t'); *out++ = Ch(';');
break;
case Ch('&'):
*out++ = Ch('&'); *out++ = Ch('a'); *out++ = Ch('m'); *out++ = Ch('p'); *out++ = Ch(';');
break;
default:
*out++ = *begin; // No expansion, copy character
}
}
++begin; // Step to next character
}
return out;
}
// Fill given output iterator with repetitions of the same character
template<class OutIt, class Ch>
inline OutIt fill_chars(OutIt out, int n, Ch ch)
{
for (int i = 0; i < n; ++i)
*out++ = ch;
return out;
}
// Find character
template<class Ch, Ch ch>
inline bool find_char(const Ch *begin, const Ch *end)
{
while (begin != end)
if (*begin++ == ch)
return true;
return false;
}
///////////////////////////////////////////////////////////////////////////
// Internal printing operations
template<class OutIt, class Ch>
inline OutIt print_children(OutIt out, const xml_node<Ch> *node, int flags, int indent);
template<class OutIt, class Ch>
inline OutIt print_attributes(OutIt out, const xml_node<Ch> *node, int flags);
template<class OutIt, class Ch>
inline OutIt print_data_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
template<class OutIt, class Ch>
inline OutIt print_cdata_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
template<class OutIt, class Ch>
inline OutIt print_element_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
template<class OutIt, class Ch>
inline OutIt print_declaration_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
template<class OutIt, class Ch>
inline OutIt print_comment_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
template<class OutIt, class Ch>
inline OutIt print_doctype_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
template<class OutIt, class Ch>
inline OutIt print_pi_node(OutIt out, const xml_node<Ch> *node, int flags, int indent);
// Print node
template<class OutIt, class Ch>
inline OutIt print_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
{
// Print proper node type
switch (node->type())
{
// Document
case node_document:
out = print_children(out, node, flags, indent);
break;
// Element
case node_element:
out = print_element_node(out, node, flags, indent);
break;
// Data
case node_data:
out = print_data_node(out, node, flags, indent);
break;
// CDATA
case node_cdata:
out = print_cdata_node(out, node, flags, indent);
break;
// Declaration
case node_declaration:
out = print_declaration_node(out, node, flags, indent);
break;
// Comment
case node_comment:
out = print_comment_node(out, node, flags, indent);
break;
// Doctype
case node_doctype:
out = print_doctype_node(out, node, flags, indent);
break;
// Pi
case node_pi:
out = print_pi_node(out, node, flags, indent);
break;
// Unknown
default:
assert(0);
break;
}
// If indenting not disabled, add line break after node
if (!(flags & print_no_indenting))
*out = Ch('\n'), ++out;
// Return modified iterator
return out;
}
// Print children of the node
template<class OutIt, class Ch>
inline OutIt print_children(OutIt out, const xml_node<Ch> *node, int flags, int indent)
{
for (xml_node<Ch> *child = node->first_node(); child; child = child->next_sibling())
out = print_node(out, child, flags, indent);
return out;
}
// Print attributes of the node
template<class OutIt, class Ch>
inline OutIt print_attributes(OutIt out, const xml_node<Ch> *node, int flags)
{
for (xml_attribute<Ch> *attribute = node->first_attribute(); attribute; attribute = attribute->next_attribute())
{
if (attribute->name() && attribute->value())
{
// Print attribute name
*out = Ch(' '), ++out;
out = copy_chars(attribute->name(), attribute->name() + attribute->name_size(), out);
*out = Ch('='), ++out;
// Print attribute value using appropriate quote type
if (find_char<Ch, Ch('"')>(attribute->value(), attribute->value() + attribute->value_size()))
{
*out = Ch('\''), ++out;
out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('"'), out);
*out = Ch('\''), ++out;
}
else
{
*out = Ch('"'), ++out;
out = copy_and_expand_chars(attribute->value(), attribute->value() + attribute->value_size(), Ch('\''), out);
*out = Ch('"'), ++out;
}
}
}
return out;
}
// Print data node
template<class OutIt, class Ch>
inline OutIt print_data_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
{
assert(node->type() == node_data);
if (!(flags & print_no_indenting))
out = fill_chars(out, indent, Ch('\t'));
out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
return out;
}
// Print data node
template<class OutIt, class Ch>
inline OutIt print_cdata_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
{
assert(node->type() == node_cdata);
if (!(flags & print_no_indenting))
out = fill_chars(out, indent, Ch('\t'));
*out = Ch('<'); ++out;
*out = Ch('!'); ++out;
*out = Ch('['); ++out;
*out = Ch('C'); ++out;
*out = Ch('D'); ++out;
*out = Ch('A'); ++out;
*out = Ch('T'); ++out;
*out = Ch('A'); ++out;
*out = Ch('['); ++out;
out = copy_chars(node->value(), node->value() + node->value_size(), out);
*out = Ch(']'); ++out;
*out = Ch(']'); ++out;
*out = Ch('>'); ++out;
return out;
}
// Print element node
template<class OutIt, class Ch>
inline OutIt print_element_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
{
assert(node->type() == node_element);
// Print element name and attributes, if any
if (!(flags & print_no_indenting))
out = fill_chars(out, indent, Ch('\t'));
*out = Ch('<'), ++out;
out = copy_chars(node->name(), node->name() + node->name_size(), out);
out = print_attributes(out, node, flags);
// If node is childless
if (node->value_size() == 0 && !node->first_node())
{
// Print childless node tag ending
*out = Ch('/'), ++out;
*out = Ch('>'), ++out;
}
else
{
// Print normal node tag ending
*out = Ch('>'), ++out;
// Test if node contains a single data node only (and no other nodes)
xml_node<Ch> *child = node->first_node();
if (!child)
{
// If node has no children, only print its value without indenting
out = copy_and_expand_chars(node->value(), node->value() + node->value_size(), Ch(0), out);
}
else if (child->next_sibling() == 0 && child->type() == node_data)
{
// If node has a sole data child, only print its value without indenting
out = copy_and_expand_chars(child->value(), child->value() + child->value_size(), Ch(0), out);
}
else
{
// Print all children with full indenting
if (!(flags & print_no_indenting))
*out = Ch('\n'), ++out;
out = print_children(out, node, flags, indent + 1);
if (!(flags & print_no_indenting))
out = fill_chars(out, indent, Ch('\t'));
}
// Print node end
*out = Ch('<'), ++out;
*out = Ch('/'), ++out;
out = copy_chars(node->name(), node->name() + node->name_size(), out);
*out = Ch('>'), ++out;
}
return out;
}
// Print declaration node
template<class OutIt, class Ch>
inline OutIt print_declaration_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
{
// Print declaration start
if (!(flags & print_no_indenting))
out = fill_chars(out, indent, Ch('\t'));
*out = Ch('<'), ++out;
*out = Ch('?'), ++out;
*out = Ch('x'), ++out;
*out = Ch('m'), ++out;
*out = Ch('l'), ++out;
// Print attributes
out = print_attributes(out, node, flags);
// Print declaration end
*out = Ch('?'), ++out;
*out = Ch('>'), ++out;
return out;
}
// Print comment node
template<class OutIt, class Ch>
inline OutIt print_comment_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
{
assert(node->type() == node_comment);
if (!(flags & print_no_indenting))
out = fill_chars(out, indent, Ch('\t'));
*out = Ch('<'), ++out;
*out = Ch('!'), ++out;
*out = Ch('-'), ++out;
*out = Ch('-'), ++out;
out = copy_chars(node->value(), node->value() + node->value_size(), out);
*out = Ch('-'), ++out;
*out = Ch('-'), ++out;
*out = Ch('>'), ++out;
return out;
}
// Print doctype node
template<class OutIt, class Ch>
inline OutIt print_doctype_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
{
assert(node->type() == node_doctype);
if (!(flags & print_no_indenting))
out = fill_chars(out, indent, Ch('\t'));
*out = Ch('<'), ++out;
*out = Ch('!'), ++out;
*out = Ch('D'), ++out;
*out = Ch('O'), ++out;
*out = Ch('C'), ++out;
*out = Ch('T'), ++out;
*out = Ch('Y'), ++out;
*out = Ch('P'), ++out;
*out = Ch('E'), ++out;
*out = Ch(' '), ++out;
out = copy_chars(node->value(), node->value() + node->value_size(), out);
*out = Ch('>'), ++out;
return out;
}
// Print pi node
template<class OutIt, class Ch>
inline OutIt print_pi_node(OutIt out, const xml_node<Ch> *node, int flags, int indent)
{
assert(node->type() == node_pi);
if (!(flags & print_no_indenting))
out = fill_chars(out, indent, Ch('\t'));
*out = Ch('<'), ++out;
*out = Ch('?'), ++out;
out = copy_chars(node->name(), node->name() + node->name_size(), out);
*out = Ch(' '), ++out;
out = copy_chars(node->value(), node->value() + node->value_size(), out);
*out = Ch('?'), ++out;
*out = Ch('>'), ++out;
return out;
}
}
//! \endcond
///////////////////////////////////////////////////////////////////////////
// Printing
//! Prints XML to given output iterator.
//! \param out Output iterator to print to.
//! \param node Node to be printed. Pass xml_document to print entire document.
//! \param flags Flags controlling how XML is printed.
//! \return Output iterator pointing to position immediately after last character of printed text.
template<class OutIt, class Ch>
inline OutIt print(OutIt out, const xml_node<Ch> &node, int flags = 0)
{
return internal::print_node(out, &node, flags, 0);
}
#ifndef RAPIDXML_NO_STREAMS
//! Prints XML to given output stream.
//! \param out Output stream to print to.
//! \param node Node to be printed. Pass xml_document to print entire document.
//! \param flags Flags controlling how XML is printed.
//! \return Output stream.
template<class Ch>
inline std::basic_ostream<Ch> &print(std::basic_ostream<Ch> &out, const xml_node<Ch> &node, int flags = 0)
{
print(std::ostream_iterator<Ch>(out), node, flags);
return out;
}
//! Prints formatted XML to given output stream. Uses default printing flags. Use print() function to customize printing process.
//! \param out Output stream to print to.
//! \param node Node to be printed.
//! \return Output stream.
template<class Ch>
inline std::basic_ostream<Ch> &operator <<(std::basic_ostream<Ch> &out, const xml_node<Ch> &node)
{
return print(out, node);
}
#endif
}
#endif
+37 -37
View File
@@ -1,37 +1,37 @@
// stb_dxt.cpp - Real-Time DXT1/DXT5 compressor
// Based on original by fabian "ryg" giesen v1.04
// Custom version, modified by Yann Collet
//
/*
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
You can contact the author at :
- RygsDXTc source repository : http://code.google.com/p/rygsdxtc/
*/
#define STB_DXT_IMPLEMENTATION
#include "stb_dxt.h"
// stb_dxt.cpp - Real-Time DXT1/DXT5 compressor
// Based on original by fabian "ryg" giesen v1.04
// Custom version, modified by Yann Collet
//
/*
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
You can contact the author at :
- RygsDXTc source repository : http://code.google.com/p/rygsdxtc/
*/
#define STB_DXT_IMPLEMENTATION
#include "stb_dxt.h"
+1043 -1043
View File
File diff suppressed because it is too large Load Diff
+9 -9
View File
@@ -1,9 +1,9 @@
Treat the license for this code as though it were the Apache-2.0 license,
WITH THE FOLLOWING MODIFICATIONS:
If you integrate LayeredFS into your launcher of choice, you MUST NOT modify the
existing commandline argument names.
If you add any commandline arguments, they MUST begin with `--layered-`.
I'm sure this lax wording is not legally binding, but please don't be an asshole.
Treat the license for this code as though it were the Apache-2.0 license,
WITH THE FOLLOWING MODIFICATIONS:
If you integrate LayeredFS into your launcher of choice, you MUST NOT modify the
existing commandline argument names.
If you add any commandline arguments, they MUST begin with `--layered-`.
I'm sure this lax wording is not legally binding, but please don't be an asshole.
+38 -38
View File
@@ -1,38 +1,38 @@
#include <string.h>
#include <windows.h>
#include <shellapi.h>
#include "config.h"
#include "utils.h"
#define VERBOSE_FLAG L"--layered-verbose"
#define DEVMODE_FLAG L"--layered-devmode"
namespace layeredfs {
config_t config{};
void load_config(void) {
LPWSTR *szArglist;
int nArgs;
int i;
szArglist = CommandLineToArgvW(GetCommandLineW(), &nArgs);
if (NULL == szArglist) {
return;
}
for (i = 0; i < nArgs; i++) {
if (lstrcmpW(szArglist[i], VERBOSE_FLAG) == 0) {
config.verbose_logs = true;
} else if (lstrcmpW(szArglist[i], DEVMODE_FLAG) == 0) {
config.developer_mode = true;
}
}
// Free memory allocated for CommandLineToArgvW arguments.
LocalFree(szArglist);
logf("Options: %ls=%d %ls=%d", VERBOSE_FLAG, config.verbose_logs, DEVMODE_FLAG, config.developer_mode);
}
}
#include <string.h>
#include <windows.h>
#include <shellapi.h>
#include "config.h"
#include "utils.h"
#define VERBOSE_FLAG L"--layered-verbose"
#define DEVMODE_FLAG L"--layered-devmode"
namespace layeredfs {
config_t config{};
void load_config(void) {
LPWSTR *szArglist;
int nArgs;
int i;
szArglist = CommandLineToArgvW(GetCommandLineW(), &nArgs);
if (NULL == szArglist) {
return;
}
for (i = 0; i < nArgs; i++) {
if (lstrcmpW(szArglist[i], VERBOSE_FLAG) == 0) {
config.verbose_logs = true;
} else if (lstrcmpW(szArglist[i], DEVMODE_FLAG) == 0) {
config.developer_mode = true;
}
}
// Free memory allocated for CommandLineToArgvW arguments.
LocalFree(szArglist);
logf("Options: %ls=%d %ls=%d", VERBOSE_FLAG, config.verbose_logs, DEVMODE_FLAG, config.developer_mode);
}
}
+13 -13
View File
@@ -1,13 +1,13 @@
#pragma once
namespace layeredfs {
typedef struct config {
bool verbose_logs = false;
bool developer_mode = false;
} config_t;
extern config_t config;
void load_config(void);
}
#pragma once
namespace layeredfs {
typedef struct config {
bool verbose_logs = false;
bool developer_mode = false;
} config_t;
extern config_t config;
void load_config(void);
}
+847 -847
View File
File diff suppressed because it is too large Load Diff
+14 -14
View File
@@ -1,14 +1,14 @@
#pragma once
#include <windows.h>
#include "avs/core.h"
namespace layeredfs {
extern time_t dll_time;
extern bool initialized;
int hook_avs_fs_lstat(const char *name, struct avs::core::avs_stat *st);
avs::core::avs_file_t hook_avs_fs_open(const char *name, uint16_t mode, int flags);
int init(void);
}
#pragma once
#include <windows.h>
#include "avs/core.h"
namespace layeredfs {
extern time_t dll_time;
extern bool initialized;
int hook_avs_fs_lstat(const char *name, struct avs::core::avs_stat *st);
avs::core::avs_file_t hook_avs_fs_open(const char *name, uint16_t mode, int flags);
int init(void);
}
+227 -227
View File
@@ -1,227 +1,227 @@
#include <windows.h>
#include <algorithm>
#include <unordered_map>
#include <unordered_set>
#include "modpath_handler.h"
#include "config.h"
#include "utils.h"
using std::nullopt;
namespace layeredfs {
typedef struct {
std::string name;
std::unordered_set<string> contents;
} mod_contents_t;
std::vector<mod_contents_t> cached_mods;
std::unordered_set<string> walk_dir(const string &path, const string &root) {
std::unordered_set<string> result;
WIN32_FIND_DATAA ffd;
auto contents = FindFirstFileA((path + "/*").c_str(), &ffd);
if (contents != INVALID_HANDLE_VALUE) {
do {
if (!strcmp(ffd.cFileName, ".") ||
!strcmp(ffd.cFileName, "..")) {
continue;
}
string result_path;
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
result_path = root + ffd.cFileName + "/";
logf_verbose(" %s", result_path.c_str());
auto subdir_walk = walk_dir(path + "/" + ffd.cFileName, result_path);
result.insert(subdir_walk.begin(), subdir_walk.end());
} else {
result_path = root + ffd.cFileName;
logf_verbose(" %s", result_path.c_str());
}
result.insert(result_path);
} while (FindNextFileA(contents, &ffd) != 0);
FindClose(contents);
}
return result;
}
void cache_mods(void) {
if (config.developer_mode)
return;
// this is a bit hacky
config.developer_mode = true;
auto avail_mods = available_mods();
config.developer_mode = false;
for (auto &dir : avail_mods) {
logf_verbose("Walking %s", dir.c_str());
mod_contents_t mod;
mod.name = dir;
mod.contents = walk_dir(dir, "");
cached_mods.push_back(mod);
}
}
optional<string> normalise_path(const string &path) {
auto data_pos = path.find("data/");
auto data2_pos = string::npos;
if (data_pos == string::npos) {
data2_pos = path.find("data2/");
if (data2_pos == string::npos)
return nullopt;
}
auto actual_pos = (data_pos != string::npos) ? data_pos : data2_pos;
// if data2 was found, use root data2/.../... instead of just .../...
auto offset = (data2_pos != string::npos) ? 0 : strlen("data/");
auto data_str = path.substr(actual_pos + offset);
// nuke backslash
string_replace(data_str, "\\", "/");
// nuke double slash
string_replace(data_str, "//", "/");
return data_str;
}
vector<string> available_mods() {
vector<string> ret;
string mod_root = MOD_FOLDER "/";
if (config.developer_mode) {
WIN32_FIND_DATAA ffd;
auto mods = FindFirstFileA(MOD_FOLDER "/*", &ffd);
if (mods != INVALID_HANDLE_VALUE) {
do {
if (!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
!strcmp(ffd.cFileName, ".") ||
!strcmp(ffd.cFileName, "..") ||
!strcmp(ffd.cFileName, "_cache")) {
continue;
}
ret.push_back(mod_root + ffd.cFileName);
} while (FindNextFileA(mods, &ffd) != 0);
FindClose(mods);
}
} else {
for (auto &dir : cached_mods) {
ret.push_back(dir.name);
}
}
std::sort(ret.begin(), ret.end());
return ret;
}
bool mkdir_p(string &path) {
/* Adapted from http://stackoverflow.com/a/2336245/119527 */
const size_t len = strlen(path.c_str());
char _path[MAX_PATH + 1];
char *p;
errno = 0;
/* Copy string so its mutable */
if (len > sizeof(_path) - 1) {
return false;
}
strncpy(_path, path.c_str(), MAX_PATH);
_path[MAX_PATH] = '\0';
/* Iterate the string */
for (p = _path + 1; *p; p++) {
if (*p == '/') {
/* Temporarily truncate */
*p = '\0';
if (!CreateDirectoryA(_path, NULL) && GetLastError() != ERROR_ALREADY_EXISTS) {
return false;
}
*p = '/';
}
}
if (!CreateDirectoryA(_path, NULL)) {
if (GetLastError() != ERROR_ALREADY_EXISTS) {
return false;
}
}
return true;
}
// same for files and folders when cached
optional<string> find_first_cached_item(const string &norm_path) {
for (auto &dir : cached_mods) {
auto file_search = dir.contents.find(norm_path);
if (file_search == dir.contents.end()) {
continue;
}
return dir.name + "/" + *file_search;
}
return nullopt;
}
optional<string> find_first_modfile(const string &norm_path) {
if (config.developer_mode) {
for (auto &dir : available_mods()) {
auto mod_path = dir + "/" + norm_path;
if (file_exists(mod_path.c_str())) {
return mod_path;
}
}
} else {
return find_first_cached_item(norm_path);
}
return nullopt;
}
optional<string> find_first_modfolder(const string &norm_path) {
if (config.developer_mode) {
for (auto &dir : available_mods()) {
auto mod_path = dir + "/" + norm_path;
if (folder_exists(mod_path.c_str())) {
return mod_path;
}
}
} else {
return find_first_cached_item(norm_path + "/");
}
return nullopt;
}
vector<string> find_all_modfile(const string &norm_path) {
vector<string> ret;
if (config.developer_mode) {
for (auto &dir : available_mods()) {
auto mod_path = dir + "/" + norm_path;
if (file_exists(mod_path.c_str())) {
ret.push_back(mod_path);
}
}
} else {
for (auto &dir : cached_mods) {
auto file_search = dir.contents.find(norm_path);
if (file_search == dir.contents.end()) {
continue;
}
ret.push_back(dir.name + "/" + *file_search);
}
}
// needed for consistency when hashing names
std::sort(ret.begin(), ret.end());
return ret;
}
}
#include <windows.h>
#include <algorithm>
#include <unordered_map>
#include <unordered_set>
#include "modpath_handler.h"
#include "config.h"
#include "utils.h"
using std::nullopt;
namespace layeredfs {
typedef struct {
std::string name;
std::unordered_set<string> contents;
} mod_contents_t;
std::vector<mod_contents_t> cached_mods;
std::unordered_set<string> walk_dir(const string &path, const string &root) {
std::unordered_set<string> result;
WIN32_FIND_DATAA ffd;
auto contents = FindFirstFileA((path + "/*").c_str(), &ffd);
if (contents != INVALID_HANDLE_VALUE) {
do {
if (!strcmp(ffd.cFileName, ".") ||
!strcmp(ffd.cFileName, "..")) {
continue;
}
string result_path;
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
result_path = root + ffd.cFileName + "/";
logf_verbose(" %s", result_path.c_str());
auto subdir_walk = walk_dir(path + "/" + ffd.cFileName, result_path);
result.insert(subdir_walk.begin(), subdir_walk.end());
} else {
result_path = root + ffd.cFileName;
logf_verbose(" %s", result_path.c_str());
}
result.insert(result_path);
} while (FindNextFileA(contents, &ffd) != 0);
FindClose(contents);
}
return result;
}
void cache_mods(void) {
if (config.developer_mode)
return;
// this is a bit hacky
config.developer_mode = true;
auto avail_mods = available_mods();
config.developer_mode = false;
for (auto &dir : avail_mods) {
logf_verbose("Walking %s", dir.c_str());
mod_contents_t mod;
mod.name = dir;
mod.contents = walk_dir(dir, "");
cached_mods.push_back(mod);
}
}
optional<string> normalise_path(const string &path) {
auto data_pos = path.find("data/");
auto data2_pos = string::npos;
if (data_pos == string::npos) {
data2_pos = path.find("data2/");
if (data2_pos == string::npos)
return nullopt;
}
auto actual_pos = (data_pos != string::npos) ? data_pos : data2_pos;
// if data2 was found, use root data2/.../... instead of just .../...
auto offset = (data2_pos != string::npos) ? 0 : strlen("data/");
auto data_str = path.substr(actual_pos + offset);
// nuke backslash
string_replace(data_str, "\\", "/");
// nuke double slash
string_replace(data_str, "//", "/");
return data_str;
}
vector<string> available_mods() {
vector<string> ret;
string mod_root = MOD_FOLDER "/";
if (config.developer_mode) {
WIN32_FIND_DATAA ffd;
auto mods = FindFirstFileA(MOD_FOLDER "/*", &ffd);
if (mods != INVALID_HANDLE_VALUE) {
do {
if (!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
!strcmp(ffd.cFileName, ".") ||
!strcmp(ffd.cFileName, "..") ||
!strcmp(ffd.cFileName, "_cache")) {
continue;
}
ret.push_back(mod_root + ffd.cFileName);
} while (FindNextFileA(mods, &ffd) != 0);
FindClose(mods);
}
} else {
for (auto &dir : cached_mods) {
ret.push_back(dir.name);
}
}
std::sort(ret.begin(), ret.end());
return ret;
}
bool mkdir_p(string &path) {
/* Adapted from http://stackoverflow.com/a/2336245/119527 */
const size_t len = strlen(path.c_str());
char _path[MAX_PATH + 1];
char *p;
errno = 0;
/* Copy string so its mutable */
if (len > sizeof(_path) - 1) {
return false;
}
strncpy(_path, path.c_str(), MAX_PATH);
_path[MAX_PATH] = '\0';
/* Iterate the string */
for (p = _path + 1; *p; p++) {
if (*p == '/') {
/* Temporarily truncate */
*p = '\0';
if (!CreateDirectoryA(_path, NULL) && GetLastError() != ERROR_ALREADY_EXISTS) {
return false;
}
*p = '/';
}
}
if (!CreateDirectoryA(_path, NULL)) {
if (GetLastError() != ERROR_ALREADY_EXISTS) {
return false;
}
}
return true;
}
// same for files and folders when cached
optional<string> find_first_cached_item(const string &norm_path) {
for (auto &dir : cached_mods) {
auto file_search = dir.contents.find(norm_path);
if (file_search == dir.contents.end()) {
continue;
}
return dir.name + "/" + *file_search;
}
return nullopt;
}
optional<string> find_first_modfile(const string &norm_path) {
if (config.developer_mode) {
for (auto &dir : available_mods()) {
auto mod_path = dir + "/" + norm_path;
if (file_exists(mod_path.c_str())) {
return mod_path;
}
}
} else {
return find_first_cached_item(norm_path);
}
return nullopt;
}
optional<string> find_first_modfolder(const string &norm_path) {
if (config.developer_mode) {
for (auto &dir : available_mods()) {
auto mod_path = dir + "/" + norm_path;
if (folder_exists(mod_path.c_str())) {
return mod_path;
}
}
} else {
return find_first_cached_item(norm_path + "/");
}
return nullopt;
}
vector<string> find_all_modfile(const string &norm_path) {
vector<string> ret;
if (config.developer_mode) {
for (auto &dir : available_mods()) {
auto mod_path = dir + "/" + norm_path;
if (file_exists(mod_path.c_str())) {
ret.push_back(mod_path);
}
}
} else {
for (auto &dir : cached_mods) {
auto file_search = dir.contents.find(norm_path);
if (file_search == dir.contents.end()) {
continue;
}
ret.push_back(dir.name + "/" + *file_search);
}
}
// needed for consistency when hashing names
std::sort(ret.begin(), ret.end());
return ret;
}
}
+29 -29
View File
@@ -1,29 +1,29 @@
#pragma once
#include <string>
#include <vector>
#if 0
#include <experimental/optional>
using std::experimental::optional;
#else
#include <optional>
using std::optional;
#endif
using std::string;
using std::vector;
#define MOD_FOLDER "./data_mods"
#define CACHE_FOLDER MOD_FOLDER "/_cache"
namespace layeredfs {
void cache_mods(void);
vector<string> available_mods();
optional<string> normalise_path(const string &path);
optional<string> find_first_modfile(const string &norm_path);
optional<string> find_first_modfolder(const string &norm_path);
vector<string> find_all_modfile(const string &norm_path);
bool mkdir_p(string &path);
}
#pragma once
#include <string>
#include <vector>
#if 0
#include <experimental/optional>
using std::experimental::optional;
#else
#include <optional>
using std::optional;
#endif
using std::string;
using std::vector;
#define MOD_FOLDER "./data_mods"
#define CACHE_FOLDER MOD_FOLDER "/_cache"
namespace layeredfs {
void cache_mods(void);
vector<string> available_mods();
optional<string> normalise_path(const string &path);
optional<string> find_first_modfile(const string &norm_path);
optional<string> find_first_modfolder(const string &norm_path);
vector<string> find_all_modfile(const string &norm_path);
bool mkdir_p(string &path);
}
+69 -69
View File
@@ -1,69 +1,69 @@
#include "texture_packer.h"
#include <algorithm>
#include "3rd_party/GuillotineBinPack.h"
using namespace rbp;
namespace layeredfs {
Bitmap::Bitmap(const string &name, int width, int height)
: name(name), width(width), height(height) {
}
bool pack_textures(vector<Bitmap *> &textures, vector<Packer *> &packed_textures) {
std::sort(textures.begin(), textures.end(), [](const Bitmap *a, const Bitmap *b) {
return (a->width * a->height) < (b->width * b->height);
});
// pack the bitmaps
while (!textures.empty()) {
auto packer = new Packer(MAX_TEXTURE);
packer->Pack(textures);
packed_textures.push_back(packer);
// failed
if (packer->bitmaps.empty())
return false;
}
return true;
}
Packer::Packer(int max_size)
: width(max_size), height(max_size) {
}
void Packer::Pack(vector<Bitmap *> &bitmaps) {
GuillotineBinPack packer(width, height);
int ww = 0;
int hh = 0;
while (!bitmaps.empty()) {
auto bitmap = bitmaps.back();
Rect rect = packer.Insert(bitmap->width, bitmap->height, false,
GuillotineBinPack::FreeRectChoiceHeuristic::RectBestAreaFit,
GuillotineBinPack::GuillotineSplitHeuristic::SplitLongerAxis);
if (rect.width == 0 || rect.height == 0)
break;
bitmap->packX = rect.x;
bitmap->packY = rect.y;
this->bitmaps.push_back(bitmap);
bitmaps.pop_back();
ww = std::max(rect.x + rect.width, ww);
hh = std::max(rect.y + rect.height, hh);
}
while (width / 2 >= ww)
width /= 2;
while (height / 2 >= hh)
height /= 2;
}
}
#include "texture_packer.h"
#include <algorithm>
#include "3rd_party/GuillotineBinPack.h"
using namespace rbp;
namespace layeredfs {
Bitmap::Bitmap(const string &name, int width, int height)
: name(name), width(width), height(height) {
}
bool pack_textures(vector<Bitmap *> &textures, vector<Packer *> &packed_textures) {
std::sort(textures.begin(), textures.end(), [](const Bitmap *a, const Bitmap *b) {
return (a->width * a->height) < (b->width * b->height);
});
// pack the bitmaps
while (!textures.empty()) {
auto packer = new Packer(MAX_TEXTURE);
packer->Pack(textures);
packed_textures.push_back(packer);
// failed
if (packer->bitmaps.empty())
return false;
}
return true;
}
Packer::Packer(int max_size)
: width(max_size), height(max_size) {
}
void Packer::Pack(vector<Bitmap *> &bitmaps) {
GuillotineBinPack packer(width, height);
int ww = 0;
int hh = 0;
while (!bitmaps.empty()) {
auto bitmap = bitmaps.back();
Rect rect = packer.Insert(bitmap->width, bitmap->height, false,
GuillotineBinPack::FreeRectChoiceHeuristic::RectBestAreaFit,
GuillotineBinPack::GuillotineSplitHeuristic::SplitLongerAxis);
if (rect.width == 0 || rect.height == 0)
break;
bitmap->packX = rect.x;
bitmap->packY = rect.y;
this->bitmaps.push_back(bitmap);
bitmaps.pop_back();
ww = std::max(rect.x + rect.width, ww);
hh = std::max(rect.y + rect.height, hh);
}
while (width / 2 >= ww)
width /= 2;
while (height / 2 >= hh)
height /= 2;
}
}
+35 -35
View File
@@ -1,35 +1,35 @@
#pragma once
#define MAX_TEXTURE 4096
#include <string>
#include <vector>
using std::string;
using std::vector;
namespace layeredfs {
struct Bitmap {
string name;
int width;
int height;
int packX;
int packY;
Bitmap(const string &name, int width, int height);
};
struct Packer {
int width;
int height;
vector<Bitmap *> bitmaps;
Packer(int max_size);
void Pack(vector<Bitmap *> &bitmaps);
};
bool pack_textures(vector<Bitmap *> &textures, vector<Packer *> &packed_textures);
}
#pragma once
#define MAX_TEXTURE 4096
#include <string>
#include <vector>
using std::string;
using std::vector;
namespace layeredfs {
struct Bitmap {
string name;
int width;
int height;
int packX;
int packY;
Bitmap(const string &name, int width, int height);
};
struct Packer {
int width;
int height;
vector<Bitmap *> bitmaps;
Packer(int max_size);
void Pack(vector<Bitmap *> &bitmaps);
};
bool pack_textures(vector<Bitmap *> &textures, vector<Packer *> &packed_textures);
}
+185 -185
View File
@@ -1,185 +1,185 @@
#include "utils.h"
#include "avs/core.h"
#include "util/utils.h"
namespace layeredfs {
char *snprintf_auto(const char *fmt, ...) {
va_list argList;
va_start(argList, fmt);
size_t len = vsnprintf(NULL, 0, fmt, argList);
auto s = (char *) malloc(len + 1);
vsnprintf(s, len + 1, fmt, argList);
va_end(argList);
return s;
}
int string_ends_with(const char *str, const char *suffix) {
size_t str_len = strlen(str);
size_t suffix_len = strlen(suffix);
return
(str_len >= suffix_len) &&
(0 == strcmp(str + (str_len - suffix_len), suffix));
}
void string_replace(std::string &str, const char *from, const char *to) {
auto to_len = strlen(to);
auto from_len = strlen(from);
size_t offset = 0;
for (auto pos = str.find(from); pos != std::string::npos; pos = str.find(from, offset)) {
str.replace(pos, from_len, to);
// avoid recursion if to contains from
offset = pos + to_len;
}
}
wchar_t *str_widen(const char *src) {
int nchars;
wchar_t *result;
nchars = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
if (!nchars) {
abort();
}
result = (wchar_t *) malloc(nchars * sizeof(wchar_t));
if (!MultiByteToWideChar(CP_ACP, 0, src, -1, result, nchars)) {
abort();
}
return result;
}
bool file_exists(const char *name) {
auto res = avs::core::avs_fs_open(name, 1, 420);
if (res > 0)
avs::core::avs_fs_close(res);
return res > 0;
}
bool folder_exists(const char *name) {
WIN32_FIND_DATAA ffd;
HANDLE hFind = FindFirstFileA(name, &ffd);
if (hFind == INVALID_HANDLE_VALUE || !(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
return false;
}
FindClose(hFind);
return true;
}
time_t file_time(const char *path) {
auto wide = str_widen(path);
auto hFile = CreateFileW(wide, // file to open
GENERIC_READ, // open for reading
FILE_SHARE_READ, // share for reading
NULL, // default security
OPEN_EXISTING, // existing file only
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, // normal file
NULL); // no attr. template
free(wide);
if (hFile == INVALID_HANDLE_VALUE)
return 0;
FILETIME mtime;
GetFileTime(hFile, NULL, NULL, &mtime);
CloseHandle(hFile);
ULARGE_INTEGER result;
result.LowPart = mtime.dwLowDateTime;
result.HighPart = mtime.dwHighDateTime;
return result.QuadPart;
}
LONG time(void) {
SYSTEMTIME time;
GetSystemTime(&time);
return (time.wSecond * 1000) + time.wMilliseconds;
}
uint8_t *lz_compress(uint8_t *input, size_t input_length, size_t *compressed_length) {
// check if cstream is unavailable
if (avs::core::cstream_create == nullptr) {
return lz_compress_dummy(input, input_length, compressed_length);
} else {
/*
* Compression using cstream
*/
auto compressor = avs::core::cstream_create(avs::core::CSTREAM_AVSLZ_COMPRESS);
if (!compressor) {
logf("Couldn't create");
return NULL;
}
compressor->in_buf = input;
compressor->in_size = (uint32_t) input_length;
// worst case, for every 8 bytes there will be an extra flag byte
auto to_add = MAX(input_length / 8, 1);
auto compress_size = input_length + to_add;
auto compress_buffer = (unsigned char*)malloc(compress_size);
compressor->out_buf = compress_buffer;
compressor->out_size = (uint32_t) compress_size;
bool ret;
ret = avs::core::cstream_operate(compressor);
if (!ret && !compressor->in_size) {
compressor->in_buf = NULL;
compressor->in_size = -1;
ret = avs::core::cstream_operate(compressor);
}
if (!ret) {
logf("Couldn't operate");
return NULL;
}
if (avs::core::cstream_finish(compressor)) {
logf("Couldn't finish");
return NULL;
}
*compressed_length = compress_size - compressor->out_size;
avs::core::cstream_destroy(compressor);
return compress_buffer;
}
}
uint8_t *lz_compress_dummy(uint8_t *input, size_t input_length, size_t *compressed_length) {
uint8_t *output = (uint8_t *) malloc(input_length + input_length / 8 + 9);
uint8_t *cur_byte = &output[0];
// copy data blocks
for (size_t n = 0; n < input_length / 8; n++) {
// fake flag
*cur_byte++ = 0xFF;
// uncompressed data
for (size_t i = 0; i < 8; i++) {
*cur_byte++ = input[n * 8 + i];
}
}
// remaining bytes
int extra_bytes = input_length % 8;
if (extra_bytes == 0) {
*cur_byte++ = 0x00;
} else {
*cur_byte++ = 0xFF >> (8 - extra_bytes);
for (size_t i = input_length - extra_bytes; i < input_length; i++) {
*cur_byte++ = input[i];
}
for (size_t i = 0; i < 4; i++) {
*cur_byte++ = 0x00;
}
}
// calculate size
*compressed_length = (size_t) (cur_byte - &output[0]);
return output;
}
}
#include "utils.h"
#include "avs/core.h"
#include "util/utils.h"
namespace layeredfs {
char *snprintf_auto(const char *fmt, ...) {
va_list argList;
va_start(argList, fmt);
size_t len = vsnprintf(NULL, 0, fmt, argList);
auto s = (char *) malloc(len + 1);
vsnprintf(s, len + 1, fmt, argList);
va_end(argList);
return s;
}
int string_ends_with(const char *str, const char *suffix) {
size_t str_len = strlen(str);
size_t suffix_len = strlen(suffix);
return
(str_len >= suffix_len) &&
(0 == strcmp(str + (str_len - suffix_len), suffix));
}
void string_replace(std::string &str, const char *from, const char *to) {
auto to_len = strlen(to);
auto from_len = strlen(from);
size_t offset = 0;
for (auto pos = str.find(from); pos != std::string::npos; pos = str.find(from, offset)) {
str.replace(pos, from_len, to);
// avoid recursion if to contains from
offset = pos + to_len;
}
}
wchar_t *str_widen(const char *src) {
int nchars;
wchar_t *result;
nchars = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
if (!nchars) {
abort();
}
result = (wchar_t *) malloc(nchars * sizeof(wchar_t));
if (!MultiByteToWideChar(CP_ACP, 0, src, -1, result, nchars)) {
abort();
}
return result;
}
bool file_exists(const char *name) {
auto res = avs::core::avs_fs_open(name, 1, 420);
if (res > 0)
avs::core::avs_fs_close(res);
return res > 0;
}
bool folder_exists(const char *name) {
WIN32_FIND_DATAA ffd;
HANDLE hFind = FindFirstFileA(name, &ffd);
if (hFind == INVALID_HANDLE_VALUE || !(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
return false;
}
FindClose(hFind);
return true;
}
time_t file_time(const char *path) {
auto wide = str_widen(path);
auto hFile = CreateFileW(wide, // file to open
GENERIC_READ, // open for reading
FILE_SHARE_READ, // share for reading
NULL, // default security
OPEN_EXISTING, // existing file only
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, // normal file
NULL); // no attr. template
free(wide);
if (hFile == INVALID_HANDLE_VALUE)
return 0;
FILETIME mtime;
GetFileTime(hFile, NULL, NULL, &mtime);
CloseHandle(hFile);
ULARGE_INTEGER result;
result.LowPart = mtime.dwLowDateTime;
result.HighPart = mtime.dwHighDateTime;
return result.QuadPart;
}
LONG time(void) {
SYSTEMTIME time;
GetSystemTime(&time);
return (time.wSecond * 1000) + time.wMilliseconds;
}
uint8_t *lz_compress(uint8_t *input, size_t input_length, size_t *compressed_length) {
// check if cstream is unavailable
if (avs::core::cstream_create == nullptr) {
return lz_compress_dummy(input, input_length, compressed_length);
} else {
/*
* Compression using cstream
*/
auto compressor = avs::core::cstream_create(avs::core::CSTREAM_AVSLZ_COMPRESS);
if (!compressor) {
logf("Couldn't create");
return NULL;
}
compressor->in_buf = input;
compressor->in_size = (uint32_t) input_length;
// worst case, for every 8 bytes there will be an extra flag byte
auto to_add = MAX(input_length / 8, 1);
auto compress_size = input_length + to_add;
auto compress_buffer = (unsigned char*)malloc(compress_size);
compressor->out_buf = compress_buffer;
compressor->out_size = (uint32_t) compress_size;
bool ret;
ret = avs::core::cstream_operate(compressor);
if (!ret && !compressor->in_size) {
compressor->in_buf = NULL;
compressor->in_size = -1;
ret = avs::core::cstream_operate(compressor);
}
if (!ret) {
logf("Couldn't operate");
return NULL;
}
if (avs::core::cstream_finish(compressor)) {
logf("Couldn't finish");
return NULL;
}
*compressed_length = compress_size - compressor->out_size;
avs::core::cstream_destroy(compressor);
return compress_buffer;
}
}
uint8_t *lz_compress_dummy(uint8_t *input, size_t input_length, size_t *compressed_length) {
uint8_t *output = (uint8_t *) malloc(input_length + input_length / 8 + 9);
uint8_t *cur_byte = &output[0];
// copy data blocks
for (size_t n = 0; n < input_length / 8; n++) {
// fake flag
*cur_byte++ = 0xFF;
// uncompressed data
for (size_t i = 0; i < 8; i++) {
*cur_byte++ = input[n * 8 + i];
}
}
// remaining bytes
int extra_bytes = input_length % 8;
if (extra_bytes == 0) {
*cur_byte++ = 0x00;
} else {
*cur_byte++ = 0xFF >> (8 - extra_bytes);
for (size_t i = input_length - extra_bytes; i < input_length; i++) {
*cur_byte++ = input[i];
}
for (size_t i = 0; i < 4; i++) {
*cur_byte++ = 0x00;
}
}
// calculate size
*compressed_length = (size_t) (cur_byte - &output[0]);
return output;
}
}
+28 -28
View File
@@ -1,28 +1,28 @@
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
#include <string>
#include "util/logging.h"
#include "config.h"
#define logf(fmt,...) {char*b=snprintf_auto(fmt,##__VA_ARGS__);log_misc("layeredfs","{}",b?b:":(");if(b)free(b);} void()
#define logf_verbose(...) if (config.verbose_logs) {logf(__VA_ARGS__);} void()
namespace layeredfs {
char *snprintf_auto(const char *fmt, ...);
int string_ends_with(const char *str, const char *suffix);
void string_replace(std::string &str, const char *from, const char *to);
wchar_t *str_widen(const char *src);
bool file_exists(const char *name);
bool folder_exists(const char *name);
time_t file_time(const char *path);
LONG time(void);
uint8_t *lz_compress(uint8_t *input, size_t input_length, size_t *compressed_length);
uint8_t *lz_compress_dummy(uint8_t *input, size_t input_length, size_t *compressed_length);
}
#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
#include <string>
#include "util/logging.h"
#include "config.h"
#define logf(fmt,...) {char*b=snprintf_auto(fmt,##__VA_ARGS__);log_misc("layeredfs","{}",b?b:":(");if(b)free(b);} void()
#define logf_verbose(...) if (config.verbose_logs) {logf(__VA_ARGS__);} void()
namespace layeredfs {
char *snprintf_auto(const char *fmt, ...);
int string_ends_with(const char *str, const char *suffix);
void string_replace(std::string &str, const char *from, const char *to);
wchar_t *str_widen(const char *src);
bool file_exists(const char *name);
bool folder_exists(const char *name);
time_t file_time(const char *path);
LONG time(void);
uint8_t *lz_compress(uint8_t *input, size_t input_length, size_t *compressed_length);
uint8_t *lz_compress_dummy(uint8_t *input, size_t input_length, size_t *compressed_length);
}