initial commit

This commit is contained in:
Thomas Fussell 2014-05-06 17:28:38 -04:00
commit d646cfcaa1
54 changed files with 6221 additions and 0 deletions

51
.clang-format Normal file
View File

@ -0,0 +1,51 @@
---
Language: Cpp
AccessModifierOffset: -4
ConstructorInitializerIndentWidth: 4
AlignEscapedNewlinesLeft: false
AlignTrailingComments: false
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AllowShortFunctionsOnASingleLine: true
AlwaysBreakTemplateDeclarations: false
AlwaysBreakBeforeMultilineStrings: false
BreakBeforeBinaryOperators: false
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BinPackParameters: true
ColumnLimit: 0
ConstructorInitializerAllOnOneLineOrOnePerLine: true
DerivePointerBinding: false
ExperimentalAutoDetectBinPacking: false
IndentCaseLabels: false
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakString: 1000
PenaltyBreakFirstLessLess: 120
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PointerBindsToType: false
SpacesBeforeTrailingComments: 1
Cpp11BracedListStyle: true
Standard: Cpp11
IndentWidth: 4
TabWidth: 8
UseTab: Never
BreakBeforeBraces: Allman
IndentFunctionDeclarationAfterType: false
SpacesInParentheses: false
SpacesInAngles: false
SpaceInEmptyParentheses: false
SpacesInCStyleCastParentheses: false
SpacesInContainerLiterals: true
SpaceBeforeAssignmentOperators: true
ContinuationIndentWidth: 4
CommentPragmas: '^ IWYU pragma:'
SpaceBeforeParens: Never
...

63
.gitattributes vendored Normal file
View File

@ -0,0 +1,63 @@
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto
###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain

11
.gitignore vendored Normal file
View File

@ -0,0 +1,11 @@
Debug/
Release/
*.obj
*.sdf
*.suo
*.opensdf
*.vcxproj.user
*.o
#*#
*~
.DS_Store

25
README.md Normal file
View File

@ -0,0 +1,25 @@
xlnt
====
Introduction
----
xlnt is a c++ library that reads and write XLSX files. The API is roughly based on openpyxl, a python XLSX library. It is still very much a work in progress, but I expect the basic functionality to be working in the near future.
Building
----
It compiles in all of the major compilers. Currently it is being built in GCC 4.8.2, MSVC 12, and Clang 3.3.
Workspaces for Visual Studio, XCode, and GNU Make can be created using premake and the premake5.lua file in the build directory.
Dependencies
----
xlnt requires the following libraries:
- [libopc v0.0.3 + mce + plib](http://libopc.codeplex.com/)
- [zlib v1.2.5](https://github.com/madler/zlib)
- [libxml2 v2.7.7](http://xmlsoft.org/index.html)
- [python v2.7+](https://www.python.org/)
- [pugixml v1.4](http://pugixml.org/)
License
----
xlnt is currently released under the terms of the MIT License.

84
build/premake5.lua Normal file
View File

@ -0,0 +1,84 @@
solution "xlnt"
configurations { "Debug", "Release" }
platforms { "x64" }
location ("./" .. _ACTION)
configuration "not windows"
buildoptions {
"-std=c++11",
"-Wno-unknown-pragmas"
}
configuration "Debug"
flags { "Symbols" }
optimize "Off"
configuration "Release"
optimize "Full"
project "xlnt.test"
kind "ConsoleApp"
language "C++"
targetname "xlnt.test"
includedirs {
"$(opc_prefix)",
"$(opc_prefix)/config",
"$(opc_prefix)/plib/config/msvc/plib/include",
"$(opc_prefix)/third_party/libxml2-2.7.7/include",
"$(cxxtest_prefix)"
}
defines { "WIN32" }
files {
"../source/tests/**.h",
"../source/tests/runner-autogen.cpp"
}
links {
"xlnt",
"Shlwapi",
"mce",
"opc",
"plib",
"xml",
"zlib"
}
prebuildcommands { "cxxtestgen --runner=ParenPrinter -o ../../source/tests/runner-autogen.cpp ../../source/tests/packaging/*.h" }
libdirs { "$(opc_prefix)/win32/x64/Debug" }
flags {
"Unicode",
"NoEditAndContinue",
"NoManifest",
"NoPCH"
}
configuration "Debug"
targetdir "../bin/debug"
configuration "Release"
flags { "LinkTimeOptimization" }
targetdir "../bin/release"
project "xlnt"
kind "StaticLib"
language "C++"
warnings "Extra"
targetdir "../lib/"
includedirs {
"$(opc_prefix)",
"$(opc_prefix)/config",
"$(opc_prefix)/plib/config/msvc/plib/include",
"$(opc_prefix)/third_party/libxml2-2.7.7/include",
"../include/xlnt"
}
defines { "WIN32" }
files {
"../source/**.cpp",
"../source/**.h",
"../include/**.h"
}
excludes {
"../source/tests/**.cpp",
"../source/tests/**.h"
}
flags {
"Unicode",
"NoEditAndContinue",
"NoManifest",
"NoPCH"
}
configuration "Debug"
flags { "FatalWarnings" }

8
docs/samples/sample1.cpp Normal file
View File

@ -0,0 +1,8 @@
#include "../include/xlnt/reader.h"
int main()
{
auto wb = xlnt::reader::load_workbook("empty_book.xlsx");
auto sheet_ranges = wb.get_sheet_by_name("range names");
std::cout << (std::string)sheet_ranges.cell("D18").value() << std::endl;
}

43
include/xlnt/cell.h Normal file
View File

@ -0,0 +1,43 @@
/*
Copyright (c) 2012-2014 Thomas Fussell
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#pragma once
#include <memory>
#include "variant.h"
namespace xlnt {
class cell_impl;
class cell
{
public:
cell();
variant value();
private:
std::shared_ptr<cell_impl> impl_;
};
} // namespace xlnt

30
include/xlnt/ooxml.h Normal file
View File

@ -0,0 +1,30 @@
/*
Copyright (c) 2012-2014 Thomas Fussell
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#pragma once
namespace xlnt {
class ooxml
{
};
} // namespace xlnt

44
include/xlnt/range.h Normal file
View File

@ -0,0 +1,44 @@
/*
Copyright (c) 2012-2014 Thomas Fussell
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#pragma once
#include <string>
#include <unordered_map>
#include "cell.h"
namespace xlnt {
class range_impl;
class range
{
public:
range();
cell cell(const std::string &address);
private:
std::shared_ptr<range_impl> impl_;
};
} // namespace xlnt

36
include/xlnt/reader.h Normal file
View File

@ -0,0 +1,36 @@
/*
Copyright (c) 2012-2014 Thomas Fussell
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#pragma once
#include <string>
#include "workbook.h"
namespace xlnt {
class reader
{
public:
static workbook load_workbook(const std::string &filename);
};
} // namespace xlnt

30
include/xlnt/style.h Normal file
View File

@ -0,0 +1,30 @@
/*
Copyright (c) 2012-2014 Thomas Fussell
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#pragma once
namespace xlnt {
class style
{
};
} // namespace xlnt

356
include/xlnt/variant.h Normal file
View File

@ -0,0 +1,356 @@
/*
Copyright (c) 2012-2014 Thomas Fussell
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
/** @file variant.h
* @brief A dynamic container holding one of the seven JSON primitives.
*
* Declaration of variant class which represents a dynamic type. It can be assigned any
* one of the following value types as defined in RFC 4627: false, null, true,
* object, array, number, string.
*
* @author Thomas A. Fussell (tfussell)
*/
#pragma once
#include <exception>
#include <string>
#include <unordered_map>
#include <vector>
namespace xlnt {
/**
* A dynamic type exception may be raised when an operation is attempted
* on a dynamic type which does not support it. For example, trying to
* index an integer type.
*/
class dynamic_type_exception : public std::runtime_error
{
public:
dynamic_type_exception() : std::runtime_error("Error: wrong type")
{
}
};
/**
* Must be forward declared so that object and array can store pointers to this
* heretofore incomplete type.
*/
class variant;
/**
* A variant class can be dynamically assigned to one of the following: null, true,
* false, number, string.
*
* Note: This class uses a long double to store its dynamic number values. This
* is consistent with JavaScript's number type, but it may limit the precision
* on very large or very small numbers and introduce rounding errors.
*/
class variant
{
private:
/**
* An enumeration of possible dynamic types that the containing class may assume.
*/
enum Type
{
T_Null, /**< null */
T_True, /**< true */
T_False, /**< false */
T_Number, /**< number */
T_String, /**< string */
};
public:
#pragma region Constructors
/**
* Constructs a new empty variant of null type.
*/
variant() : type_(T_Null) { }
/**
* Constructs a new variant class of type T_True or T_False if the given paramter, b, is true or false respectively.
*/
variant(bool b) : type_(b ? T_True : T_False) { }
/**
* Constructs a new variant class of type T_Number with a dynamic numeric value based on the given parameter, i.
*/
variant(int i) : type_(T_Number), number_(i) { }
/**
* Constructs a new variant class of type T_Number with a dynamic numeric value based on the given parameter, i.
*/
variant(long long i) : type_(T_Number), number_(static_cast<long double>(i)) { }
/**
* Constructs a new variant class of type T_Number with a dynamic numeric value based on the given parameter, d.
*/
variant(double d) : type_(T_Number), number_(d) { }
/**
* Constructs a new variant class of type T_Number with a dynamic numeric value based on the given parameter, d.
*/
variant(long double d) : type_(T_Number), number_(d) { }
/**
* Constructs a new variant class of type T_String with a dynamic string value based on the given parameter, s.
*/
variant(const char *s) : type_(T_String), string_(s) { }
/**
* Constructs a new variant class of type T_String with a dynamic string value based on the given parameter, s.
*/
variant(const std::string &s) : type_(T_String), string_(s) { }
/**
* Constructs a new variant as a deep-copy of an existing object.
*/
variant(const variant &v) { *this = v; }
/**
* If this is a container type, destroys contents and clears the container.
*/
~variant();
#pragma endregion
#pragma region Operators
/**
* Assigns the fields of this object to those of the given parameter, rhs, by creating a deep-copy of containers.
*/
variant &operator=(const variant &rhs);
/**
* Returns true if the types of this object and the given parameter, rhs, are equal and checks the corresponding
* field for equality. For container types, this recursively checks for element-by-element equality in the same
* way.
*/
bool operator==(const variant &rhs) const;
/**
* Returns the negation of the result of the equality operator.
*/
bool operator!=(const variant &rhs) const { return !(*this == rhs); }
#pragma endregion
#pragma region Casts
template <class T> T cast() const;
template <>
bool variant::cast() const
{
if(type_ == T_True)
{
return true;
}
else if(type_ == T_False)
{
return false;
}
throw dynamic_type_exception();
}
template <>
int variant::cast() const
{
if(type_ == T_Number)
{
return static_cast<int>(number_);
}
throw dynamic_type_exception();
}
template <>
double variant::cast() const
{
if(type_ == T_Number)
{
return static_cast<double>(number_);
}
throw dynamic_type_exception();
}
template <>
long long variant::cast() const
{
if(type_ == T_Number)
{
return static_cast<long long>(number_);
}
throw dynamic_type_exception();
}
template <>
long double variant::cast() const
{
if(type_ == T_Number)
{
return number_;
}
throw dynamic_type_exception();
}
template <>
std::string variant::cast() const
{
if(type_ == T_String)
{
return string_;
}
throw dynamic_type_exception();
}
/**
* See: bool ToBool() const
*/
operator bool() const { return cast<bool>(); }
/**
* See: int ToInt() const
*/
operator int() const { return cast<int>(); }
/**
* See: double ToDouble() const
*/
operator double() const { return cast<double>(); }
/**
* See: long long ToLongLong() const
*/
operator long long() const { return cast<long long>(); }
/**
* See: long double ToLongDouble() const
*/
operator long double() const { return cast<long double>(); }
/**
* See: std::string ToString() const
*/
operator std::string() const { return cast<std::string>(); }
#pragma endregion
#pragma region Type checks
/**
* Returns true if the type of this object is T_Null.
*/
bool isnull() const { return type_ == T_Null; }
/**
* Returns true if the type of this object is T_True.
*/
bool istrue() const { return type_ == T_True; }
/**
* Returns true if the type of this object is T_False.
*/
bool isfalse() const { return type_ == T_False; }
/**
* Returns true if the type of this object is T_True or T_False.
*/
bool isboolean() const { return istrue() || isfalse(); }
/**
* Returns true if the type of this object is T_Number.
*/
bool isnumber() const { return type_ == T_Number; }
/**
* Returns true if the type of this object is T_Number and number has no decimal part.
*/
bool isint() const { return isnumber() && !isfloat(); }
/**
* Returns true if the type of this object is T_Number and number has a decimal part.
*/
bool isfloat() const { return isnumber() && ceil(number_) != number_; }
/**
* Returns true if the type of this object is T_String.
*/
bool isstring() const { return type_ == T_String; }
#pragma endregion
private:
/**
* Constructs a new variant of the given type with an optional parameter indicating whether this
* variant preserves order (only relevant if it is of type T_Object).
*/
variant(Type type) : type_(type) { }
/**
* Attempts to convert the current value of this object to a bool.
* This will raise an error if the internal type is not T_True or T_False.
*/
bool asbool() const;
/*
* Attempts to convert the current value of this object to an int.
* This will raise an error if the internal type is not T_Number.
* This conversion may overflow.
*/
int asint() const;
/*
* Attempts to convert the current value of this object to a double.
* This will raise an error if the internal type is not T_Number.
* This conversion may overflow.
*/
double asdouble() const;
/*
* Attempts to convert the current value of this object to a long long int.
* This will raise an error if the internal type is not T_Number.
*/
long long aslonglong() const;
/*
* Attempts to convert the current value of this object to a long double.
* This will raise an error if the internal type is not T_Number.
*/
long double aslongdouble() const;
/*
* Attempts to convert the current value of this object to a string.
* This will raise an error if the internal type is not T_String.
*/
std::string asstring() const;
Type type_; /**< Dynamic type of the contained value. */
long double number_; /**< Holder for numeric value if this has type T_Number */
std::string string_; /**< Holder for string value if this has type T_String */
};
extern const variant $; /**< Special variant which represents null JSON literal */
} // namespace xlnt

43
include/xlnt/workbook.h Normal file
View File

@ -0,0 +1,43 @@
/*
Copyright (c) 2012-2014 Thomas Fussell
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#pragma once
#include <string>
#include "worksheet.h"
namespace xlnt {
class workbook_impl;
class workbook
{
public:
workbook();
worksheet get_sheet_by_name(const std::string &sheet_name);
private:
std::shared_ptr<workbook_impl> impl_;
};
} // namespace xlnt

41
include/xlnt/worksheet.h Normal file
View File

@ -0,0 +1,41 @@
/*
Copyright (c) 2012-2014 Thomas Fussell
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#pragma once
#include <string>
#include "range.h"
namespace xlnt {
class worksheet_impl;
class worksheet : public range
{
public:
worksheet();
private:
std::shared_ptr<worksheet_impl> impl_;
};
} // namespace xlnt

36
include/xlnt/writer.h Normal file
View File

@ -0,0 +1,36 @@
/*
Copyright (c) 2012-2014 Thomas Fussell
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#pragma once
#include <string>
#include "workbook.h"
namespace xlnt {
class writer
{
public:
static void save_workbook(const workbook &workbook, const std::string &filename);
};
} // namespace xlnt

502
source/misc/color.cpp Normal file
View File

@ -0,0 +1,502 @@
#include <algorithm>
#include <iomanip>
#include <sstream>
#include <vector>
#include "color.h"
#include "enum_iterator.h"
namespace xlnt {
const color color::AliceBlue = color::from_argb(255, 240, 248, 255);
const color color::AntiqueWhite = color::from_argb(255, 250, 235, 215);
const color color::Aqua = color::from_argb(255, 0, 255, 255);
const color color::Aquamarine = color::from_argb(255, 127, 255, 212);
const color color::Azure = color::from_argb(255, 240, 255, 255);
const color color::Beige = color::from_argb(255, 245, 245, 220);
const color color::Bisque = color::from_argb(255, 255, 228, 196);
const color color::Black = color::from_argb(255, 0, 0, 0);
const color color::BlanchedAlmond = color::from_argb(255, 255, 235, 205);
const color color::Blue = color::from_argb(255, 0, 0, 255);
const color color::BlueViolet = color::from_argb(255, 138, 43, 226);
const color color::Brown = color::from_argb(255, 165, 42, 42);
const color color::BurlyWood = color::from_argb(255, 222, 184, 135);
const color color::CadetBlue = color::from_argb(255, 95, 158, 160);
const color color::Chartreuse = color::from_argb(255, 127, 255, 0);
const color color::Chocolate = color::from_argb(255, 210, 105, 30);
const color color::Coral = color::from_argb(255, 255, 127, 80);
const color color::CornflowerBlue = color::from_argb(255, 100, 149, 237);
const color color::Cornsilk = color::from_argb(255, 255, 248, 220);
const color color::Crimson = color::from_argb(255, 220, 20, 60);
const color color::Cyan = color::from_argb(255, 0, 255, 255);
const color color::DarkBlue = color::from_argb(255, 0, 0, 139);
const color color::DarkCyan = color::from_argb(255, 0, 139, 139);
const color color::DarkGoldenrod = color::from_argb(255, 184, 134, 11);
const color color::DarkGray = color::from_argb(255, 169, 169, 169);
const color color::DarkGreen = color::from_argb(255, 0, 100, 0);
const color color::DarkKhaki = color::from_argb(255, 189, 183, 107);
const color color::DarkMagenta = color::from_argb(255, 139, 0, 139);
const color color::DarkOliveGreen = color::from_argb(255, 85, 107, 47);
const color color::DarkOrange = color::from_argb(255, 255, 140, 0);
const color color::DarkOrchid = color::from_argb(255, 153, 50, 204);
const color color::DarkRed = color::from_argb(255, 139, 0, 0);
const color color::DarkSalmon = color::from_argb(255, 233, 150, 122);
const color color::DarkSeaGreen = color::from_argb(255, 143, 188, 143);
const color color::DarkSlateBlue = color::from_argb(255, 72, 61, 139);
const color color::DarkSlateGray = color::from_argb(255, 47, 79, 79);
const color color::DarkTurquoise = color::from_argb(255, 0, 206, 209);
const color color::DarkViolet = color::from_argb(255, 148, 0, 211);
const color color::DeepPink = color::from_argb(255, 255, 20, 147);
const color color::DeepSkyBlue = color::from_argb(255, 0, 191, 255);
const color color::DimGray = color::from_argb(255, 105, 105, 105);
const color color::DodgerBlue = color::from_argb(255, 30, 144, 255);
const color color::Firebrick = color::from_argb(255, 178, 34, 34);
const color color::FloralWhite = color::from_argb(255, 255, 250, 240);
const color color::ForestGreen = color::from_argb(255, 34, 139, 34);
const color color::Fuchsia = color::from_argb(255, 255, 0, 255);
const color color::Gainsboro = color::from_argb(255, 220, 220, 220);
const color color::GhostWhite = color::from_argb(255, 248, 248, 255);
const color color::Gold = color::from_argb(255, 255, 215, 0);
const color color::Goldenrod = color::from_argb(255, 218, 165, 32);
const color color::Gray = color::from_argb(255, 128, 128, 128);
const color color::Green = color::from_argb(255, 0, 128, 0);
const color color::GreenYellow = color::from_argb(255, 173, 255, 47);
const color color::Honeydew = color::from_argb(255, 240, 255, 240);
const color color::HotPink = color::from_argb(255, 255, 105, 180);
const color color::IndianRed = color::from_argb(255, 205, 92, 92);
const color color::Indigo = color::from_argb(255, 75, 0, 130);
const color color::Ivory = color::from_argb(255, 255, 255, 240);
const color color::Khaki = color::from_argb(255, 240, 230, 140);
const color color::Lavender = color::from_argb(255, 230, 230, 250);
const color color::LavenderBlush = color::from_argb(255, 255, 240, 245);
const color color::LawnGreen = color::from_argb(255, 124, 252, 0);
const color color::LemonChiffon = color::from_argb(255, 255, 250, 205);
const color color::LightBlue = color::from_argb(255, 173, 216, 230);
const color color::LightCoral = color::from_argb(255, 240, 128, 128);
const color color::LightCyan = color::from_argb(255, 224, 255, 255);
const color color::LightGoldenrodYellow = color::from_argb(255, 250, 250, 210);
const color color::LightGray = color::from_argb(255, 211, 211, 211);
const color color::LightGreen = color::from_argb(255, 144, 238, 144);
const color color::LightPink = color::from_argb(255, 255, 182, 193);
const color color::LightSalmon = color::from_argb(255, 255, 160, 122);
const color color::LightSeaGreen = color::from_argb(255, 32, 178, 170);
const color color::LightSkyBlue = color::from_argb(255, 135, 206, 250);
const color color::LightSlateGray = color::from_argb(255, 119, 136, 153);
const color color::LightSteelBlue = color::from_argb(255, 176, 196, 222);
const color color::LightYellow = color::from_argb(255, 255, 255, 224);
const color color::Lime = color::from_argb(255, 0, 255, 0);
const color color::LimeGreen = color::from_argb(255, 50, 205, 50);
const color color::Linen = color::from_argb(255, 250, 240, 230);
const color color::Magenta = color::from_argb(255, 255, 0, 255);
const color color::Maroon = color::from_argb(255, 128, 0, 0);
const color color::MediumAquamarine = color::from_argb(255, 102, 205, 170);
const color color::MediumBlue = color::from_argb(255, 0, 0, 205);
const color color::MediumOrchid = color::from_argb(255, 186, 85, 211);
const color color::MediumPurple = color::from_argb(255, 147, 112, 219);
const color color::MediumSeaGreen = color::from_argb(255, 60, 179, 113);
const color color::MediumSlateBlue = color::from_argb(255, 123, 104, 238);
const color color::MediumSpringGreen = color::from_argb(255, 0, 250, 154);
const color color::MediumTurquoise = color::from_argb(255, 72, 209, 204);
const color color::MediumVioletRed = color::from_argb(255, 199, 21, 133);
const color color::MidnightBlue = color::from_argb(255, 25, 25, 112);
const color color::MintCream = color::from_argb(255, 245, 255, 250);
const color color::MistyRose = color::from_argb(255, 255, 228, 225);
const color color::Moccasin = color::from_argb(255, 255, 228, 181);
const color color::NavajoWhite = color::from_argb(255, 255, 222, 173);
const color color::Navy = color::from_argb(255, 0, 0, 128);
const color color::OldLace = color::from_argb(255, 253, 245, 230);
const color color::Olive = color::from_argb(255, 128, 128, 0);
const color color::OliveDrab = color::from_argb(255, 107, 142, 35);
const color color::Orange = color::from_argb(255, 255, 165, 0);
const color color::OrangeRed = color::from_argb(255, 255, 69, 0);
const color color::Orchid = color::from_argb(255, 218, 112, 214);
const color color::PaleGoldenrod = color::from_argb(255, 238, 232, 170);
const color color::PaleGreen = color::from_argb(255, 152, 251, 152);
const color color::PaleTurquoise = color::from_argb(255, 175, 238, 238);
const color color::PaleVioletRed = color::from_argb(255, 219, 112, 147);
const color color::PapayaWhip = color::from_argb(255, 255, 239, 213);
const color color::PeachPuff = color::from_argb(255, 255, 218, 185);
const color color::Peru = color::from_argb(255, 205, 133, 63);
const color color::Pink = color::from_argb(255, 255, 192, 203);
const color color::Plum = color::from_argb(255, 221, 160, 221);
const color color::PowderBlue = color::from_argb(255, 176, 224, 230);
const color color::Purple = color::from_argb(255, 128, 0, 128);
const color color::Red = color::from_argb(255, 255, 0, 0);
const color color::RosyBrown = color::from_argb(255, 188, 143, 143);
const color color::RoyalBlue = color::from_argb(255, 65, 105, 225);
const color color::SaddleBrown = color::from_argb(255, 139, 69, 19);
const color color::Salmon = color::from_argb(255, 250, 128, 114);
const color color::SandyBrown = color::from_argb(255, 244, 164, 96);
const color color::SeaGreen = color::from_argb(255, 46, 139, 87);
const color color::SeaShell = color::from_argb(255, 255, 245, 238);
const color color::Sienna = color::from_argb(255, 160, 82, 45);
const color color::Silver = color::from_argb(255, 192, 192, 192);
const color color::SkyBlue = color::from_argb(255, 135, 206, 235);
const color color::SlateBlue = color::from_argb(255, 106, 90, 205);
const color color::SlateGray = color::from_argb(255, 112, 128, 144);
const color color::Snow = color::from_argb(255, 255, 250, 250);
const color color::SpringGreen = color::from_argb(255, 0, 255, 127);
const color color::SteelBlue = color::from_argb(255, 70, 130, 180);
const color color::Tan = color::from_argb(255, 210, 180, 140);
const color color::Teal = color::from_argb(255, 0, 128, 128);
const color color::Thistle = color::from_argb(255, 216, 191, 216);
const color color::Tomato = color::from_argb(255, 255, 99, 71);
const color color::Transparent = color::from_argb(0, 0, 0, 0);
const color color::Turquoise = color::from_argb(255, 64, 224, 208);
const color color::Violet = color::from_argb(255, 238, 130, 238);
const color color::Wheat = color::from_argb(255, 245, 222, 179);
const color color::White = color::from_argb(255, 255, 255, 255);
const color color::WhiteSmoke = color::from_argb(255, 245, 245, 245);
const color color::Yellow = color::from_argb(255, 255, 255, 0);
const color color::YellowGreen = color::from_argb(255, 154, 205, 50);
const color color::Empty;
color color::from_argb(uint32_t argb)
{
return color(uint8_t(argb >> 24), uint8_t(argb >> 16), uint8_t(argb >> 8), uint8_t(argb));
}
color color::from_argb(uint8_t alpha, color base)
{
return color(alpha, base.red_, base.green_, base.blue_);
}
color color::from_argb(uint8_t r, uint8_t g, uint8_t b)
{
return color(255, r, g, b);
}
color color::from_argb(uint8_t a, uint8_t r, uint8_t g, uint8_t b)
{
return color(a, r, g, b);
}
color color::from_known_color(known_color color)
{
switch(color)
{
case known_color::AliceBlue: return AliceBlue;
case known_color::AntiqueWhite: return AntiqueWhite;
case known_color::Aqua: return Aqua;
case known_color::Aquamarine: return Aquamarine;
case known_color::Azure: return Azure;
case known_color::Beige: return Beige;
case known_color::Bisque: return Bisque;
case known_color::Black: return Black;
case known_color::BlanchedAlmond: return BlanchedAlmond;
case known_color::Blue: return Blue;
case known_color::BlueViolet: return BlueViolet;
case known_color::Brown: return Brown;
case known_color::BurlyWood: return BurlyWood;
case known_color::CadetBlue: return CadetBlue;
case known_color::Chartreuse: return Chartreuse;
case known_color::Chocolate: return Chocolate;
case known_color::Coral: return Coral;
case known_color::CornflowerBlue: return CornflowerBlue;
case known_color::Cornsilk: return Cornsilk;
case known_color::Crimson: return Crimson;
case known_color::Cyan: return Cyan;
case known_color::DarkBlue: return DarkBlue;
case known_color::DarkCyan: return DarkCyan;
case known_color::DarkGoldenrod: return DarkGoldenrod;
case known_color::DarkGray: return DarkGray;
case known_color::DarkGreen: return DarkGreen;
case known_color::DarkKhaki: return DarkKhaki;
case known_color::DarkMagenta: return DarkMagenta;
case known_color::DarkOliveGreen: return DarkOliveGreen;
case known_color::DarkOrange: return DarkOrange;
case known_color::DarkOrchid: return DarkOrchid;
case known_color::DarkRed: return DarkRed;
case known_color::DarkSalmon: return DarkSalmon;
case known_color::DarkSeaGreen: return DarkSeaGreen;
case known_color::DarkSlateBlue: return DarkSlateBlue;
case known_color::DarkSlateGray: return DarkSlateGray;
case known_color::DarkTurquoise: return DarkTurquoise;
case known_color::DarkViolet: return DarkViolet;
case known_color::DeepPink: return DeepPink;
case known_color::DeepSkyBlue: return DeepSkyBlue;
case known_color::DimGray: return DimGray;
case known_color::DodgerBlue: return DodgerBlue;
case known_color::Firebrick: return Firebrick;
case known_color::FloralWhite: return FloralWhite;
case known_color::ForestGreen: return ForestGreen;
case known_color::Fuchsia: return Fuchsia;
case known_color::Gainsboro: return Gainsboro;
case known_color::GhostWhite: return GhostWhite;
case known_color::Gold: return Gold;
case known_color::Goldenrod: return Goldenrod;
case known_color::Gray: return Gray;
case known_color::Green: return Green;
case known_color::GreenYellow: return GreenYellow;
case known_color::Honeydew: return Honeydew;
case known_color::HotPink: return HotPink;
case known_color::IndianRed: return IndianRed;
case known_color::Indigo: return Indigo;
case known_color::Ivory: return Ivory;
case known_color::Khaki: return Khaki;
case known_color::Lavender: return Lavender;
case known_color::LavenderBlush: return LavenderBlush;
case known_color::LawnGreen: return LawnGreen;
case known_color::LemonChiffon: return LemonChiffon;
case known_color::LightBlue: return LightBlue;
case known_color::LightCoral: return LightCoral;
case known_color::LightCyan: return LightCyan;
case known_color::LightGoldenrodYellow: return LightGoldenrodYellow;
case known_color::LightGray: return LightGray;
case known_color::LightGreen: return LightGreen;
case known_color::LightPink: return LightPink;
case known_color::LightSalmon: return LightSalmon;
case known_color::LightSeaGreen: return LightSeaGreen;
case known_color::LightSkyBlue: return LightSkyBlue;
case known_color::LightSlateGray: return LightSlateGray;
case known_color::LightSteelBlue: return LightSteelBlue;
case known_color::LightYellow: return LightYellow;
case known_color::Lime: return Lime;
case known_color::LimeGreen: return LimeGreen;
case known_color::Linen: return Linen;
case known_color::Magenta: return Magenta;
case known_color::Maroon: return Maroon;
case known_color::MediumAquamarine: return MediumAquamarine;
case known_color::MediumBlue: return MediumBlue;
case known_color::MediumOrchid: return MediumOrchid;
case known_color::MediumPurple: return MediumPurple;
case known_color::MediumSeaGreen: return MediumSeaGreen;
case known_color::MediumSlateBlue: return MediumSlateBlue;
case known_color::MediumSpringGreen: return MediumSpringGreen;
case known_color::MediumTurquoise: return MediumTurquoise;
case known_color::MediumVioletRed: return MediumVioletRed;
case known_color::MidnightBlue: return MidnightBlue;
case known_color::MintCream: return MintCream;
case known_color::MistyRose: return MistyRose;
case known_color::Moccasin: return Moccasin;
case known_color::NavajoWhite: return NavajoWhite;
case known_color::Navy: return Navy;
case known_color::OldLace: return OldLace;
case known_color::Olive: return Olive;
case known_color::OliveDrab: return OliveDrab;
case known_color::Orange: return Orange;
case known_color::OrangeRed: return OrangeRed;
case known_color::Orchid: return Orchid;
case known_color::PaleGoldenrod: return PaleGoldenrod;
case known_color::PaleGreen: return PaleGreen;
case known_color::PaleTurquoise: return PaleTurquoise;
case known_color::PaleVioletRed: return PaleVioletRed;
case known_color::PapayaWhip: return PapayaWhip;
case known_color::PeachPuff: return PeachPuff;
case known_color::Peru: return Peru;
case known_color::Pink: return Pink;
case known_color::Plum: return Plum;
case known_color::PowderBlue: return PowderBlue;
case known_color::Purple: return Purple;
case known_color::Red: return Red;
case known_color::RosyBrown: return RosyBrown;
case known_color::RoyalBlue: return RoyalBlue;
case known_color::SaddleBrown: return SaddleBrown;
case known_color::Salmon: return Salmon;
case known_color::SandyBrown: return SandyBrown;
case known_color::SeaGreen: return SeaGreen;
case known_color::SeaShell: return SeaShell;
case known_color::Sienna: return Sienna;
case known_color::Silver: return Silver;
case known_color::SkyBlue: return SkyBlue;
case known_color::SlateBlue: return SlateBlue;
case known_color::SlateGray: return SlateGray;
case known_color::Snow: return Snow;
case known_color::SpringGreen: return SpringGreen;
case known_color::SteelBlue: return SteelBlue;
case known_color::Tan: return Tan;
case known_color::Teal: return Teal;
case known_color::Thistle: return Thistle;
case known_color::Tomato: return Tomato;
case known_color::Turquoise: return Turquoise;
case known_color::Violet: return Violet;
case known_color::Wheat: return Wheat;
case known_color::White: return White;
case known_color::WhiteSmoke: return WhiteSmoke;
case known_color::Yellow: return Yellow;
case known_color::YellowGreen: return YellowGreen;
}
throw std::runtime_error("unknown known_color");
}
color color::from_name(const std::string &name)
{
for(auto current_color : enum_iterator<known_color>())
{
if(to_string(current_color) == name)
{
return from_known_color(current_color);
}
}
return Empty;
}
bool color::equals(color b) const
{
if(is_empty_)
{
return b.is_empty_;
}
return !b.is_empty_ && alpha_ == b.alpha_ && red_ == b.red_ && green_ == b.green_ && blue_ == b.blue_;
}
struct hsv
{
float h;
float s;
float v;
};
hsv RGBtoHSV(float red, float green, float blue)
{
hsv r;
float min = std::min({red, green, blue});
float max = std::max({red, green, blue});
r.v = max; // v
float delta = max - min;
if(max != 0)
{
r.s = delta / max; // s
}
else
{
// r = g = b = 0 // s = 0, v is undefined
r.s = 0;
r.h = -1;
return r;
}
if(red == max)
{
r.h = (green - blue) / delta; // between yellow & magenta
}
else if(green == max)
{
r.h = 2 + (blue - red) / delta; // between cyan & yellow
}
else
{
r.h = 4 + (red - green) / delta; // between magenta & cyan
}
r.h *= 60; // degrees
if(r.h < 0)
{
r.h += 360;
}
return r;
}
float color::get_brightness() const
{
return RGBtoHSV(red_, green_, blue_).v;
}
float color::get_hue() const
{
return RGBtoHSV(red_, green_, blue_).h;
}
float color::getsaturation() const
{
return RGBtoHSV(red_, green_, blue_).s;
}
bool color::is_known_color() const
{
try
{
to_known_color();
return true;
}
catch(...)
{
return false;
}
}
bool color::is_system_color() const
{
static const std::vector<known_color> system_colors = {
known_color::ActiveBorder,
known_color::ActiveCaption,
known_color::ActiveCaptionText,
known_color::AppWorkspace,
known_color::ButtonFace,
known_color::ButtonHighlight,
known_color::ButtonShadow,
known_color::Control,
known_color::ControlDark,
known_color::ControlDarkDark,
known_color::ControlLight,
known_color::ControlLightLight,
known_color::ControlText,
known_color::Desktop,
known_color::GradientActiveCaption,
known_color::GradientInactiveCaption,
known_color::GrayText,
known_color::Highlight,
known_color::HighlightText,
known_color::HotTrack,
known_color::InactiveBorder,
known_color::InactiveCaption,
known_color::InactiveCaptionText,
known_color::Info,
known_color::InfoText,
known_color::Menu,
known_color::MenuBar,
known_color::MenuHighlight,
known_color::MenuText,
known_color::ScrollBar,
known_color::Window,
known_color::WindowFrame,
known_color::WindowText
};
try
{
return std::find(system_colors.begin(), system_colors.end(), to_known_color()) != system_colors.end();
}
catch(...)
{
return false;
}
}
uint32_t color::to_argb() const
{
uint32_t argb = alpha_;
argb = argb << 8 | red_;
argb = argb << 8 | green_;
argb = argb << 8 | blue_;
return argb;
}
known_color color::to_known_color() const
{
for(auto current_color : enum_iterator<known_color>())
{
if(from_known_color(current_color) == *this)
{
return current_color;
}
}
return known_color::Unknown;
}
std::string color::get_name() const
{
try
{
return to_string(to_known_color());
}
catch(...)
{
std::stringstream stream;
stream << "#" << std::setfill('0') << std::setw(2) << std::hex;
stream << alpha_ << red_ << green_ << blue_;
return stream.str();
}
}
} // namespace xlnt

1511
source/misc/color.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,49 @@
#pragma once
#include <iterator>
namespace xlnt {
template<class enum_type>
class enum_iterator {
private:
enum_type value;
typedef typename std::underlying_type<enum_type>::type under;
public:
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef enum_type value_type;
typedef enum_type reference;
typedef enum_type* pointer;
typedef std::random_access_iterator_tag iterator_category;
enum_iterator() :value() {}
enum_iterator(const enum_iterator& rhs) : value(rhs.value) {}
explicit enum_iterator(enum_type value_) : value(value_) {}
~enum_iterator() {}
enum_iterator& operator=(const enum_iterator& rhs) { value = rhs.valud; return *this; }
enum_iterator& operator++() { value = (enum_type)(under(value) + 1); return *this; }
enum_iterator operator++(int){ enum_iterator r(*this); ++*this; return r; }
enum_iterator& operator+=(size_type o) { value = (enum_type)(under(value) + o); return *this; }
friend enum_iterator operator+(const enum_iterator& it, size_type o) { return enum_iterator((enum_type)(under(it) + o)); }
friend enum_iterator operator+(size_type o, const enum_iterator& it) { return enum_iterator((enum_type)(under(it) + o)); }
enum_iterator& operator--() { value = (enum_type)(under(value) - 1); return *this; }
enum_iterator operator--(int) { enum_iterator r(*this); --*this; return r; }
enum_iterator& operator-=(size_type o) { value = (enum_type)(under(value) + o); return *this; }
friend enum_iterator operator-(const enum_iterator& it, size_type o) { return enum_iterator((enum_type)(under(it) - o)); }
friend difference_type operator-(enum_iterator lhs, enum_iterator rhs) { return under(lhs.value) - under(rhs.value); }
reference operator*() const { return value; }
reference operator[](size_type o) const { return (enum_type)(under(value) + o); }
const enum_type* operator->() const { return &value; }
friend bool operator==(const enum_iterator& lhs, const enum_iterator& rhs) { return lhs.value == rhs.value; }
friend bool operator!=(const enum_iterator& lhs, const enum_iterator& rhs) { return lhs.value != rhs.value; }
friend bool operator<(const enum_iterator& lhs, const enum_iterator& rhs) { return lhs.value<rhs.value; }
friend bool operator>(const enum_iterator& lhs, const enum_iterator& rhs) { return lhs.value>rhs.value; }
friend bool operator<=(const enum_iterator& lhs, const enum_iterator& rhs) { return lhs.value <= rhs.value; }
friend bool operator>=(const enum_iterator& lhs, const enum_iterator& rhs) { return lhs.value >= rhs.value; }
friend void swap(const enum_iterator& lhs, const enum_iterator& rhs) { std::swap(lhs.value, rhs.value); }
enum_iterator begin() { return enum_iterator<enum_type>(enum_type::First); }
enum_iterator end() { return enum_iterator<enum_type>(enum_type::Last); }
};
} // namespace xlnt

148
source/misc/nullable.h Normal file
View File

@ -0,0 +1,148 @@
#pragma once
#include <stdexcept>
namespace xlnt {
/// <summary>
/// Represents a value type that may or may not have an assigned value.
/// </summary>
template<typename T>
struct nullable
{
public:
/// <summary>
/// Initializes a new instance of the nullable&lt;T&gt; structure with a "null" value.
/// </summary>
nullable() : has_value_(false) {}
/// <summary>
/// Initializes a new instance of the nullable&lt;T&gt; structure to the specified value.
/// </summary>
nullable(const T &value) : has_value_(true), value_(value) {}
/// <summary>
/// gets a value indicating whether the current nullable&lt;T&gt; object has a valid value of its underlying type.
/// </summary>
bool has_value() const { return has_value_; }
/// <summary>
/// gets the value of the current nullable&lt;T&gt; object if it has been assigned a valid underlying value.
/// </summary>
T get_value() const
{
if(!has_value())
{
throw std::runtime_error("invalid operation");
}
return value_;
}
/// <summary>
/// Indicates whether the current nullable&lt;T&gt; object is equal to a specified object.
/// </summary>
bool equals(const nullable<T> &other) const
{
if(!has_value())
{
return !other.has_value();
}
if(other.has_value())
{
return get_value() == other.get_value();
}
return false;
}
/// <summary>
/// Retrieves the value of the current nullable&lt;T&gt; object, or the object's default value.
/// </summary>
T get_value_or_default()
{
if(has_value())
{
return get_value();
}
return T();
}
/// <summary>
/// Retrieves the value of the current nullable&lt;T&gt; object or the specified default value.
/// </summary>
T get_value_or_default(const T &default_)
{
if(has_value())
{
return get_value();
}
return default_;
}
/// <summary>
/// Returns the value of a specified nullable&lt;T&gt; value.
/// </summary>
operator T() const
{
return get_value();
}
/// <summary>
/// Indicates whether the current nullable&lt;T&gt; object is equal to a specified object.
/// </summary>
bool operator==(nullptr_t) const
{
return !has_value_;
}
/// <summary>
/// Indicates whether the current nullable&lt;T&gt; object is not equal to a specified object.
/// </summary>
bool operator!=(nullptr_t) const
{
return has_value_;
}
/// <summary>
/// Indicates whether the current nullable&lt;T&gt; object is equal to a specified object.
/// </summary>
bool operator==(T other) const
{
return has_value_ && other == value_;
}
/// <summary>
/// Indicates whether the current nullable&lt;T&gt; object is not equal to a specified object.
/// </summary>
bool operator!=(T other) const
{
return has_value_ && other != value_;
}
/// <summary>
/// Indicates whether the current nullable&lt;T&gt; object is equal to a specified object.
/// </summary>
bool operator==(const nullable<T> &other) const
{
return equals(other);
}
/// <summary>
/// Indicates whether the current nullable&lt;T&gt; object is not equal to a specified object.
/// </summary>
bool operator!=(const nullable<T> &other) const
{
return !(*this == other);
}
private:
bool has_value_;
T value_;
};
} // namespace xlnt

85
source/misc/variant.cpp Normal file
View File

@ -0,0 +1,85 @@
/*
Copyright (c) 2012-2014 Thomas Fussell
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <string>
#include <unordered_map>
#include <vector>
#include "variant.h"
namespace xlnt {
const variant $ = variant();
variant::~variant()
{
}
variant &variant::operator=(const variant &rhs)
{
type_ = rhs.type_;
switch(type_)
{
case T_Null:
case T_True:
case T_False:
{
break;
}
case T_Number:
{
number_ = rhs.number_;
break;
}
case T_String:
{
string_ = rhs.string_;
break;
}
}
return *this;
}
bool variant::operator==(const variant &rhs) const
{
if(rhs.type_ != type_)
{
return false;
}
switch(type_)
{
case T_Null:
case T_True:
case T_False:
return true;
case T_Number:
return std::abs(number_ - rhs.number_) < 0.001;
case T_String:
return string_.compare(rhs.string_) == 0;
}
throw dynamic_type_exception();
}
} // namespace xlnt

View File

@ -0,0 +1,32 @@
#pragma once
namespace xlnt {
/// <summary>
/// Specifies the compression level for content that is stored in a part.
/// </summary>
enum class compression_option
{
/// <summary>
/// Compression is optimized for performance.
/// </summary>
Fast,
/// <summary>
/// Compression is optimized for size.
/// </summary>
Maximum,
/// <summary>
/// Compression is optimized for a balance between size and performance.
/// </summary>
Normal,
/// <summary>
/// Compression is turned off.
/// </summary>
NotCompressed,
/// <summary>
/// Compression is optimized for high performance.
/// </summary>
SuperFast
};
} // namespace xlnt

24
source/packaging/file.h Normal file
View File

@ -0,0 +1,24 @@
#pragma once
#include <string>
namespace xlnt {
/// <summary>
/// Provides static methods for the creation, copying, deletion, moving, and opening of a single file, and aids in the creation of FileStream objects.
/// </summary>
class file
{
public:
/// <summary>
/// Copies an existing file to a new file. Overwriting a file of the same name is allowed.
/// </summary>
static void copy(const std::string &source, const std::string &destination, bool overwrite = false);
/// <summary>
/// Determines whether the specified file exists.
/// </summary>
static bool exists(const std::string &path);
};
} // namespace xlnt

View File

@ -0,0 +1,28 @@
#pragma once
namespace xlnt {
/// <summary>
/// Defines constants for read, write, or read / write access to a file.
/// </summary>
enum class file_access
{
/// <summary>
/// Read access to the file. Data can be read from the file. Combine with Write for read/write access.
/// </summary>
Read = 0x01,
/// <summary>
/// Read and write access to the file. Data can be written to and read from the file.
/// </summary>
ReadWrite = 0x02,
/// <summary>
/// Write access to the file. Data can be written to the file. Combine with Read for read/write access.
/// </summary>
Write = 0x04,
/// <summary>
/// Inherit access for part from enclosing package.
/// </summary>
FromPackage = 0x08
};
} // namespace xlnt

View File

@ -0,0 +1,35 @@
#include <Windows.h>
#include "file_info.h"
namespace xlnt {
file_info::file_info(const std::string &path)
{
fullName_ = path;
}
void file_info::delete_()
{
std::wstring wFileName(fullName_.begin(), fullName_.end());
LPCWSTR lpFileName = wFileName.c_str();
BOOL result = DeleteFile(lpFileName);
if(result == 0)
{
throw std::runtime_error("delete failed: " + fullName_);
}
}
bool file_info::exists() const
{
std::wstring wFileName(fullName_.begin(), fullName_.end());
LPCWSTR lpFileName = wFileName.c_str();
DWORD dwAttrib = GetFileAttributes(lpFileName);
return dwAttrib != INVALID_FILE_ATTRIBUTES;
}
} // namespace xlnt

View File

@ -0,0 +1,148 @@
#pragma once
#include <ctime>
#include <string>
#include <tuple>
namespace xlnt {
/// <summary>
/// Provides attributes for files and directories.
/// </summary>
enum class file_attributes
{
/// <summary>
/// The file is a candidate for backup or removal.
/// </summary>
Archive,
/// <summary>
/// The file is compressed.
/// </summary>
Compressed,
/// <summary>
/// Reserved for future use.
/// </summary>
Device,
/// <summary>
/// The file is a directory.
/// </summary>
Directory,
/// <summary>
/// The file or directory is encrypted. For a file, this means that all data in the file is encrypted. For a directory, this means that encryption is the default for newly created files and directories.
/// </summary>
Encrypted,
/// <summary>
/// The file is hidden, and thus is not included in an ordinary directory listing.
/// </summary>
Hidden,
/// <summary>
/// The file or directory includes data integrity support. When this value is applied to a file, all data streams in the file have integrity support. When this value is applied to a directory, all new files and subdirectories within that directory, by default, include integrity support.
/// </summary>
IntegrityStream,
/// <summary>
/// The file is a standard file that has no special attributes. This attribute is valid only if it is used alone.
/// </summary>
Normal,
/// <summary>
/// The file or directory is excluded from the data integrity scan. When this value is applied to a directory, by default, all new files and subdirectories within that directory are excluded from data integrity.
/// </summary>
NoScrubData,
/// <summary>
/// The file will not be indexed by the operating system's content indexing service.
/// </summary>
NotContentIndexed,
/// <summary>
/// The file is offline. The data of the file is not immediately available.
/// </summary>
Offline,
/// <summary>
/// The file is read-only.
/// </summary>
ReadOnly,
/// <summary>
/// The file contains a reparse point, which is a block of user-defined data associated with a file or a directory.
/// </summary>
ReparsePoint,
/// <summary>
/// The file is a sparse file. Sparse files are typically large files whose data consists of mostly zeros.
/// </summary>
SparseFile,
/// <summary>
/// The file is a system file. That is, the file is part of the operating system or is used exclusively by the operating system.
/// </summary>
System,
/// <summary>
/// The file is temporary. A temporary file contains data that is needed while an application is executing but is not needed after the application is finished. File systems try to keep all the data in memory for quicker access rather than flushing the data back to mass storage. A temporary file should be deleted by the application as soon as it is no longer needed.
/// </summary>
Temporary
};
class file_info
{
public:
file_info(const std::string &fileName);
file_attributes get_attributes() const { return attributes_; }
void set_attributes(file_attributes attributes) { attributes_ = attributes; }
tm get_creation_time() const { return creationTime_; }
void set_creation_time(const tm &creationTime) { creationTime_ = creationTime; }
tm get_creation_time_utc() const { return time_to_utc(creationTime_); }
void set_creation_time_utc(const tm &creationTime) { creationTime_ = time_from_utc(creationTime); }
std::string get_directory_name() const { return directoryName_; }
bool exists() const;
std::string get_extension() const { return split_extension(fullName_).second; }
std::string get_full_name() const { return fullName_; }
bool IsReadOnly() const { return readOnly_; }
void set_ReadOnly(bool readOnly) { readOnly_ = readOnly; }
tm get_LastAccessTime() const { return creationTime_; }
void set_LastAccessTime(const tm &creationTime) { creationTime_ = creationTime; }
tm get_LastAccessUtc() const { return time_to_utc(creationTime_); }
void set_LastAccessUtc(const tm &creationTime) { creationTime_ = time_from_utc(creationTime); }
tm get_LastWriteTime() const { return creationTime_; }
void set_LastWriteTime(const tm &creationTime) { creationTime_ = creationTime; }
tm get_LastWriteTimeUtc() const { return time_to_utc(creationTime_); }
void set_LastWriteTimeUtc(const tm &creationTime) { creationTime_ = time_from_utc(creationTime); }
void delete_();
void encrypt();
void move_to();
void open();
void open_read();
void open_text();
void open_write();
void refresh();
void replace(const std::string &, const std::string &);
void replace(const std::string &, const std::string &, bool);
void set_access_control();
std::string to_string();
private:
static tm time_to_utc(const tm &time);
static tm time_from_utc(const tm &time);
static std::pair<std::string, std::string> split_extension(const std::string &name);
file_attributes attributes_;
tm creationTime_;
std::string directoryName_;
bool exists_;
std::string fullName_;
bool readOnly_;
tm lastAccessTime_;
tm lastWriteTime_;
int length_;
std::string path_;
};
} // namespace xlnt

View File

@ -0,0 +1,36 @@
#pragma once
namespace xlnt {
/// <summary>
/// Specifies how the operating system should open a file.
/// </summary>
enum class file_mode
{
/// <summary>
/// Opens the file if it exists and seeks to the end of the file, or creates a new file.This requires FileIOPermissionAccess.Append permission.file_mode.Append can be used only in conjunction with file_access.Write.Trying to seek to a position before the end of the file throws an IOException exception, and any attempt to read fails and throws a NotSupportedException exception.
/// </summary>
Append,
/// <summary>
/// Specifies that the operating system should create a new file. If the file already exists, it will be overwritten. This requires FileIOPermissionAccess.Write permission. file_mode.Create is equivalent to requesting that if the file does not exist, use CreateNew; otherwise, use Truncate. If the file already exists but is a hidden file, an UnauthorizedAccessException exception is thrown.
/// </summary>
Create,
/// <summary>
/// Specifies that the operating system should create a new file. This requires FileIOPermissionAccess.Write permission. If the file already exists, an IOException exception is thrown.
/// </summary>
CreateNew,
/// <summary>
/// Specifies that the operating system should open an existing file. The ability to open the file is dependent on the value specified by the file_access enumeration. A System.IO.FileNotFoundException exception is thrown if the file does not exist.
/// </summary>
Open,
/// <summary>
/// Specifies that the operating system should open a file if it exists; otherwise, a new file should be created. If the file is opened with file_access.Read, FileIOPermissionAccess.Read permission is required. If the file access is file_access.Write, FileIOPermissionAccess.Write permission is required. If the file is opened with file_access.ReadWrite, both FileIOPermissionAccess.Read and FileIOPermissionAccess.Write permissions are required.
/// </summary>
OpenOrCreate,
/// <summary>
/// Specifies that the operating system should open an existing file. When the file is opened, it should be truncated so that its size is zero bytes. This requires FileIOPermissionAccess.Write permission. Attempts to read from a file opened with file_mode.Truncate cause an ArgumentException exception.
/// </summary>
Truncate
};
} // namespace xlnt

View File

@ -0,0 +1,43 @@
#pragma once
namespace xlnt {
/// <summary>
/// Contains constants for controlling the kind of access other FileStream objects can have to the same file.
/// </summary>
enum class file_share
{
/// <summary>
/// Allows subsequent deleting of a file.
/// </summary>
Delete,
/// <summary>
/// Makes the file handle inheritable by child processes. This is not directly supported by Win32.
/// </summary>
Inheritable,
/// <summary>
/// Declines sharing of the current file. Any request to open the file (by this process or another process) will
/// fail until the file is closed.
/// </summary>
None,
/// <summary>
/// Allows subsequent opening of the file for reading. If this flag is not specified, any request to open the file
/// for reading (by this process or another process) will fail until the file is closed. However, even if this flag
/// is specified, additional permissions might still be needed to access the file.
/// </summary>
Read,
/// <summary>
/// Allows subsequent opening of the file for reading or writing. If this flag is not specified, any request to
/// open the file for reading or writing (by this process or another process) will fail until the file is closed.
/// However, even if this flag is specified, additional permissions might still be needed to access the file.
/// </summary>
ReadWrite,
/// <summary>
/// Allows subsequent opening of the file for writing. If this flag is not specified, any request to open the file
/// for writing (by this process or another process) will fail until the file is closed. However, even if this flag
/// is specified, additional permissions might still be needed to access the file.
/// </summary>
Write
};
} // namespace xlnt

View File

@ -0,0 +1,49 @@
#include <cassert>
#include <Shlwapi.h>
#include <Windows.h>
#include "File.h"
namespace xlnt {
void file::copy(const std::string &source, const std::string &destination, bool overwrite)
{
assert(source.size() + 1 < MAX_PATH);
assert(destination.size() + 1 < MAX_PATH);
std::wstring source_wide(source.begin(), source.end());
std::wstring destination_wide(destination.begin(), destination.end());
BOOL result = CopyFile(source_wide.c_str(), destination_wide.c_str(), !overwrite);
if(result == 0)
{
DWORD error = GetLastError();
if(error == ERROR_ACCESS_DENIED)
{
throw std::runtime_error("Access is denied");
}
if(error == ERROR_ENCRYPTION_FAILED)
{
throw std::runtime_error("The specified file could not be encrypted");
}
if(error == ERROR_FILE_NOT_FOUND)
{
throw std::runtime_error("The source file wasn't found");
}
if(!overwrite)
{
throw std::runtime_error("The destination file already exists");
}
throw std::runtime_error("Unknown error");
}
}
bool file::exists(const std::string &path)
{
std::wstring path_wide(path.begin(), path.end());
return PathFileExists(path_wide.c_str()) && !PathIsDirectory(path_wide.c_str());
}
} // namespace xlnt

View File

@ -0,0 +1,8 @@
#include "opc_callback_handler.h"
#include "package.h"
namespace xlnt {
} // namespace xlnt

View File

@ -0,0 +1,23 @@
#pragma once
#include <opc/opc.h>
namespace xlnt {
class opc_callback_handler
{
public:
static int read(void *context, char *buffer, int length);
static int write(void *context, const char *buffer, int length);
static int close(void *context);
static opc_ofs_t seek(void *context, opc_ofs_t ofs);
static int trim(void *context, opc_ofs_t new_size);
static int flush(void *context);
};
} // namespace xlnt

View File

@ -0,0 +1,30 @@
#pragma once
#include <array>
#include <iostream>
#include <opc/opc.h>
namespace xlnt {
class opc_streambuf : public std::streambuf
{
public:
opc_streambuf(opcContainer *container, const std::string &part_name);
opc_streambuf(const opc_streambuf &) = delete;
opc_streambuf &operator=(const opc_streambuf &) = delete;
private:
int_type underflow();
int_type uflow();
int_type pbackfail(int_type ch);
std::streamsize showmanyc();
int_type overflow(int_type ch);
int sync();
opcContainer *container_;
std::string part_name_;
std::array<char, 1024> buffer_;
};
} // namespace xlnt

View File

@ -0,0 +1,393 @@
#include <array>
#include <functional>
#include <iostream>
#include "package.h"
#include "file.h"
#include "part.h"
namespace xlnt {
class package_impl
{
public:
opcContainer *opc_container_;
std::iostream &stream_;
std::fstream file_stream_;
file_mode package_mode_;
file_access package_access_;
std::vector<xmlChar> container_buffer_;
bool open_;
package_properties package_properties_;
bool streaming_;
file_access get_file_open_access() const
{
if(!open_)
{
throw std::runtime_error("The package is not open");
}
return package_access_;
}
package_properties get_package_properties() const
{
if(!open_)
{
throw std::runtime_error("The package is not open");
}
return package_properties_;
}
package_impl(std::iostream &stream, file_mode package_mode, file_access package_access)
: stream_(stream), container_buffer_(4096), package_mode_(package_mode), package_access_(package_access)
{
open_container();
}
package_impl(const std::string &path, file_mode package_mode, file_access package_access)
: stream_(file_stream_), container_buffer_(4096), package_mode_(package_mode), package_access_(package_access)
{
switch(package_mode)
{
case file_mode::Append:
switch(package_access)
{
case file_access::Read: throw std::runtime_error("Append can only be used with file_access.Write");
case file_access::ReadWrite: throw std::runtime_error("Append can only be used with file_access.Write");
case file_access::Write:
file_stream_.open(path, std::ios::binary | std::ios::app | std::ios::out);
break;
}
break;
case file_mode::Create:
switch(package_access)
{
case file_access::Read:
file_stream_.open(path, std::ios::binary | std::ios::in);
break;
case file_access::ReadWrite:
file_stream_.open(path, std::ios::binary | std::ios::in | std::ios::out);
break;
case file_access::Write:
file_stream_.open(path, std::ios::binary | std::ios::out);
break;
}
break;
case file_mode::CreateNew:
if(!file::exists(path))
{
throw std::runtime_error("File already exists");
}
switch(package_access)
{
case file_access::Read:
file_stream_.open(path, std::ios::binary | std::ios::in);
break;
case file_access::ReadWrite:
file_stream_.open(path, std::ios::binary | std::ios::in | std::ios::out);
break;
case file_access::Write:
file_stream_.open(path, std::ios::binary | std::ios::out);
break;
}
break;
case file_mode::Open:
if(!file::exists(path))
{
throw std::runtime_error("Can't open non-existent file");
}
switch(package_access)
{
case file_access::Read:
file_stream_.open(path, std::ios::binary | std::ios::in);
break;
case file_access::ReadWrite:
file_stream_.open(path, std::ios::binary | std::ios::in | std::ios::out);
break;
case file_access::Write:
file_stream_.open(path, std::ios::binary | std::ios::out);
break;
}
break;
case file_mode::OpenOrCreate:
switch(package_access)
{
case file_access::Read:
file_stream_.open(path, std::ios::binary | std::ios::in);
break;
case file_access::ReadWrite:
file_stream_.open(path, std::ios::binary | std::ios::in | std::ios::out);
break;
case file_access::Write:
file_stream_.open(path, std::ios::binary | std::ios::out);
break;
}
break;
case file_mode::Truncate:
if(!file::exists(path))
{
throw std::runtime_error("Can't truncate non-existent file");
}
switch(package_access)
{
case file_access::Read:
file_stream_.open(path, std::ios::binary | std::ios::trunc | std::ios::in);
break;
case file_access::ReadWrite:
file_stream_.open(path, std::ios::binary | std::ios::trunc | std::ios::in | std::ios::out);
break;
case file_access::Write:
file_stream_.open(path, std::ios::binary | std::ios::trunc | std::ios::out);
break;
}
break;
}
open_container();
}
void open_container()
{
opcContainerOpenMode m;
switch(package_access_)
{
case file_access::Read:
m = opcContainerOpenMode::OPC_OPEN_READ_ONLY;
break;
case file_access::ReadWrite:
m = opcContainerOpenMode::OPC_OPEN_READ_WRITE;
break;
case file_access::Write:
m = opcContainerOpenMode::OPC_OPEN_WRITE_ONLY;
break;
default:
throw std::runtime_error("unknown file access");
}
opc_container_ = opcContainerOpenIO(&read_callback, &write_callback,
&close_callback, &seek_callback,
&trim_callback, &flush_callback, this, 4096, m, this);
open_ = true;
}
~package_impl()
{
close();
}
void close()
{
if(open_)
{
open_ = false;
opcContainerClose(opc_container_, opcContainerCloseMode::OPC_CLOSE_NOW);
opc_container_ = nullptr;
}
}
part create_part(const uri &/*part_uri*/, const std::string &/*content_type*/, compression_option /*compression*/)
{
return part();
}
void delete_part(const uri &/*part_uri*/)
{
}
void flush()
{
stream_.flush();
}
part get_part(const uri &/*part_uri*/)
{
return part();// *this, part_uri, opc_container_);
}
part_collection get_parts()
{
return part_collection();
}
int write(char *buffer, int length)
{
stream_.read(buffer, length);
auto bytes_read = stream_.gcount();
return static_cast<int>(bytes_read);
}
int read(const char *buffer, int length)
{
auto before = stream_.tellp();
stream_.write(buffer, length);
auto bytes_written = stream_.tellp() - before;
return static_cast<int>(bytes_written);
}
std::ios::pos_type seek(std::ios::pos_type offset)
{
stream_.clear();
stream_.seekg(offset);
auto current_position = stream_.tellg();
if(stream_.eof())
{
std::cout << "eof" << std::endl;
}
if(stream_.fail())
{
std::cout << "fail" << std::endl;
}
if(stream_.bad())
{
std::cout << "bad" << std::endl;
}
return current_position;
}
int trim(std::ios::pos_type /*new_size*/)
{
return 0;
}
static int read_callback(void *context, char *buffer, int length)
{
auto object = static_cast<package_impl *>(context);
return object->write(buffer, length);
}
static int write_callback(void *context, const char *buffer, int length)
{
auto object = static_cast<package_impl *>(context);
return object->read(buffer, length);
}
static int close_callback(void *context)
{
auto object = static_cast<package_impl *>(context);
object->close();
return 0;
}
static opc_ofs_t seek_callback(void *context, opc_ofs_t ofs)
{
auto object = static_cast<package_impl *>(context);
return static_cast<opc_ofs_t>(object->seek(ofs));
}
static int trim_callback(void *context, opc_ofs_t new_size)
{
auto object = static_cast<package_impl *>(context);
return object->trim(new_size);
}
static int flush_callback(void *context)
{
auto object = static_cast<package_impl *>(context);
object->flush();
return 0;
}
};
file_access package::get_file_open_access() const
{
return impl_->get_file_open_access();
}
package_properties package::get_package_properties() const
{
return impl_->get_package_properties();
}
package package::open(std::iostream &stream, file_mode package_mode, file_access package_access)
{
return package(stream, package_mode, package_access);
}
package package::open(const std::string &path, file_mode package_mode, file_access package_access, file_share /*package_share*/)
{
return package(path, package_mode, package_access);
}
package::package(std::iostream &stream, file_mode package_mode, file_access package_access)
: impl_(new package_impl(stream, package_mode, package_access))
{
open_container();
}
package::package(const std::string &path, file_mode package_mode, file_access package_access)
: impl_(new package_impl(path, package_mode, package_access))
{
}
void package::open_container()
{
impl_->open_container();
}
void package::close()
{
impl_->close();
}
part package::create_part(const uri &part_uri, const std::string &content_type, compression_option compression)
{
return impl_->create_part(part_uri, content_type, compression);
}
void package::delete_part(const uri &part_uri)
{
impl_->delete_part(part_uri);
}
void package::flush()
{
impl_->flush();
}
part package::get_part(const uri &part_uri)
{
return impl_->get_part(part_uri);
}
part_collection package::get_parts()
{
return impl_->get_parts();
}
int package::write(char *buffer, int length)
{
return impl_->write(buffer, length);
}
int package::read(const char *buffer, int length)
{
return impl_->read(buffer, length);
}
std::ios::pos_type package::seek(std::ios::pos_type offset)
{
return impl_->seek(offset);
}
int package::trim(std::ios::pos_type new_size)
{
return impl_->trim(new_size);
}
bool package::operator==(const package &comparand) const
{
return impl_.get() == comparand.impl_.get();
}
bool package::operator==(const nullptr_t &) const
{
return impl_.get() == nullptr;
}
} // namespace xlnt

137
source/packaging/package.h Normal file
View File

@ -0,0 +1,137 @@
#pragma once
#include <fstream>
#include <opc/opc.h>
#include <opc/container.h>
#include "compression_option.h"
#include "file_access.h"
#include "file_mode.h"
#include "file_share.h"
#include "opc_callback_handler.h"
#include "package_properties.h"
#include "part.h"
#include "relationship.h"
#include "target_mode.h"
#include "uri.h"
namespace xlnt {
class package_impl;
/// <summary>
/// Implements a derived subclass of the abstract Package base class—the ZipPackage class uses a
/// ZIP archive as the container store. This class should not be inherited.
/// </summary>
class package
{
public:
/// <summary>
/// Opens a package with a given IO stream, file mode, and file access setting.
/// </summary>
static package open(std::iostream &stream, file_mode package_mode, file_access package_access);
/// <summary>
/// Opens a package at a given path using a given file mode, file access, and file share setting.
/// </summary>
static package open(const std::string &path, file_mode package_mode = file_mode::OpenOrCreate,
file_access package_access = file_access::ReadWrite, file_share package_share = file_share::None);
/// <summary>
/// Saves and closes the package plus all underlying part streams.
/// </summary>
void close();
/// <summary>
/// Creates a new part with a given URI, content type, and compression option.
/// </summary>
part create_part(const uri &part_uri, const std::string &content_type, compression_option compression = compression_option::Normal);
/// <summary>
/// Creates a package-level relationship to a part with a given URI, target mode, relationship type, and identifier (ID).
/// </summary>
relationship create_relationship(const uri &part_uri, target_mode target_mode, const std::string &relationship_type, const std::string &id);
/// <summary>
/// Deletes a part with a given URI from the package.
/// </summary>
void delete_part(const uri &part_uri);
/// <summary>
/// Deletes a package-level relationship.
/// </summary>
void delete_relationship(const std::string &id);
/// <summary>
/// Saves the contents of all parts and relationships that are contained in the package.
/// </summary>
void flush();
/// <summary>
/// Returns the part with a given URI.
/// </summary>
part get_part(const uri &part_uri);
/// <summary>
/// Returns a collection of all the parts in the package.
/// </summary>
part_collection get_parts();
/// <summary>
///
/// </summary>
relationship get_relationship(const std::string &id);
/// <summary>
/// Returns the package-level relationship with a given identifier.
/// </summary>
relationship_collection get_relationships();
/// <summary>
/// Returns a collection of all the package-level relationships that match a given RelationshipType.
/// </summary>
relationship_collection get_relationships(const std::string &relationship_type);
/// <summary>
/// Indicates whether a part with a given URI is in the package.
/// </summary>
bool part_exists(const uri &part_uri);
/// <summary>
/// Indicates whether a package-level relationship with a given ID is contained in the package.
/// </summary>
bool relationship_exists(const std::string &id);
/// <summary>
/// gets the file access setting for the package.
/// </summary>
file_access get_file_open_access() const;
/// <summary>
/// gets the core properties of the package.
/// </summary>
package_properties get_package_properties() const;
bool operator==(const package &comparand) const;
bool operator==(const nullptr_t &) const;
private:
friend opc_callback_handler;
package(std::iostream &stream, file_mode package_mode, file_access package_access);
package(const std::string &path, file_mode package_mode, file_access package_access);
void open_container();
int write(char *buffer, int length);
int read(const char *buffer, int length);
std::ios::pos_type seek(std::ios::pos_type ofs);
int trim(std::ios::pos_type new_size);
std::shared_ptr<package_impl> impl_;
};
} // namespace xlnt

View File

@ -0,0 +1,198 @@
#pragma once
#include <ctime>
#include <string>
#include "../misc/nullable.h"
namespace xlnt {
/// <summary>
/// Represents the core properties of a Package.
/// </summary>
class package_properties
{
public:
/// <summary>
/// gets the category of the Package.
/// </summary>
std::string get_category() const { return category_; }
/// <summary>
/// sets the category of the Package.
/// </summary>
void set_category(const std::string &category) { category_ = category; }
/// <summary>
/// gets the category of the Package.
/// </summary>
std::string get_content_status() const { return category_; }
/// <summary>
/// sets the category of the Package.
/// </summary>
void set_content_status(const std::string &category) { category_ = category; }
/// <summary>
/// gets the category of the Package.
/// </summary>
std::string get_content_type() const { return category_; }
/// <summary>
/// sets the category of the Package.
/// </summary>
void set_content_type(const std::string &category) { category_ = category; }
/// <summary>
/// gets the category of the Package.
/// </summary>
nullable<tm> get_created() const { return created_; }
/// <summary>
/// sets the category of the Package.
/// </summary>
void set_created(const nullable<tm> &created) { created_ = created; }
/// <summary>
/// gets the category of the Package.
/// </summary>
std::string get_creator() const { return category_; }
/// <summary>
/// sets the category of the Package.
/// </summary>
void set_creator(const std::string &category) { category_ = category; }
/// <summary>
/// gets the category of the Package.
/// </summary>
std::string get_description() const { return category_; }
/// <summary>
/// sets the category of the Package.
/// </summary>
void set_description(const std::string &category) { category_ = category; }
/// <summary>
/// gets the category of the Package.
/// </summary>
std::string get_identifier() const { return category_; }
/// <summary>
/// sets the category of the Package.
/// </summary>
void set_identifier(const std::string &category) { category_ = category; }
/// <summary>
/// gets the category of the Package.
/// </summary>
std::string get_keywords() const { return category_; }
/// <summary>
/// sets the category of the Package.
/// </summary>
void set_keywords(const std::string &category) { category_ = category; }
/// <summary>
/// gets the category of the Package.
/// </summary>
std::string get_language() const { return category_; }
/// <summary>
/// sets the category of the Package.
/// </summary>
void set_language(const std::string &category) { category_ = category; }
/// <summary>
/// gets the category of the Package.
/// </summary>
std::string get_last_modified_by() const { return category_; }
/// <summary>
/// sets the category of the Package.
/// </summary>
void set_last_modified_by (const std::string &category) { category_ = category; }
/// <summary>
/// gets the category of the Package.
/// </summary>
nullable<tm> get_last_printed() const { return created_; }
/// <summary>
/// sets the category of the Package.
/// </summary>
void set_last_printed(const nullable<tm> &created) { created_ = created; }
/// <summary>
/// gets the category of the Package.
/// </summary>
nullable<tm> get_modified() const { return created_; }
/// <summary>
/// sets the category of the Package.
/// </summary>
void set_modified(const nullable<tm> &created) { created_ = created; }
/// <summary>
/// gets the category of the Package.
/// </summary>
std::string get_revision() const { return category_; }
/// <summary>
/// sets the category of the Package.
/// </summary>
void set_revision(const std::string &category) { category_ = category; }
/// <summary>
/// gets the category of the Package.
/// </summary>
std::string getsubject() const { return category_; }
/// <summary>
/// sets the category of the Package.
/// </summary>
void setsubject(const std::string &category) { category_ = category; }
/// <summary>
/// gets the category of the Package.
/// </summary>
std::string get_title() const { return category_; }
/// Ssummary>
/// gets the category of the Package.
/// </summary>
void set_title(const std::string &category) { category_ = category; }
/// <summary>
/// gets the category of the Package.
/// </summary>
std::string get_version() const { return category_; }
/// <summary>
/// sets the category of the Package.
/// </summary>
void set_version(const std::string &category) { category_ = category; }
protected:
friend class package;
private:
std::string category_;
std::string content_status_;
std::string content_type_;
nullable<tm> created_;
std::string creator_;
std::string description_;
std::string identifier_;
std::string keywords_;
std::string language_;
std::string last_modified_by_;
nullable<tm> last_printed_;
nullable<tm> modified_;
std::string revision_;
std::string subject_;
std::string title_;
std::string version_;
};
} // namespace xlnt

174
source/packaging/part.cpp Normal file
View File

@ -0,0 +1,174 @@
#include "part.h"
namespace xlnt {
class part_impl
{
public:
/// <summary>
/// Initializes a new instance of the part class with a specified parent Package, part URI, MIME content type, and compression_option.
/// </summary>
part_impl(package &package, const uri &uri_part, const std::string &mime_type = "", compression_option compression = compression_option::NotCompressed)
: package_(package),
uri_(uri_part),
content_type_(mime_type),
compression_option_(compression)
{}
part_impl(package &package, const uri &uri, opcContainer *container)
: package_(package),
uri_(uri),
container_(container)
{}
/// <summary>
/// gets the compression option of the part content stream.
/// </summary>
compression_option get_compression_option() const { return compression_option_; }
/// <summary>
/// gets the MIME type of the content stream.
/// </summary>
std::string get_content_type() const;
/// <summary>
/// gets the parent Package of the part.
/// </summary>
package &get_package() const { return package_; }
/// <summary>
/// gets the URI of the part.
/// </summary>
uri get_uri() const { return uri_; }
/// <summary>
/// Creates a part-level relationship between this part to a specified target part or external resource.
/// </summary>
std::shared_ptr<relationship> create_relationship(const uri &target_uri, target_mode target_mode, const std::string &relationship_type);
/// <summary>
/// Deletes a specified part-level relationship.
/// </summary>
void delete_relationship(const std::string &id);
/// <summary>
/// Returns the relationship that has a specified Id.
/// </summary>
relationship get_relationship(const std::string &id);
/// <summary>
/// Returns a collection of all the relationships that are owned by this part.
/// </summary>
relationship_collection get_relationships();
/// <summary>
/// Returns a collection of the relationships that match a specified RelationshipType.
/// </summary>
relationship_collection get_relationship_by_type(const std::string &relationship_type);
std::string read()
{
std::string ss;
auto part_stream = opcContainerOpenInputStream(container_, (xmlChar*)get_uri().get_OriginalString().c_str());
std::array<xmlChar, 1024> buffer;
auto bytes_read = opcContainerReadInputStream(part_stream, buffer.data(), static_cast<opc_uint32_t>(buffer.size()));
if(bytes_read > 0)
{
ss.append(std::string(buffer.begin(), buffer.begin() + bytes_read));
while(bytes_read == buffer.size())
{
auto bytes_read = opcContainerReadInputStream(part_stream, buffer.data(), static_cast<opc_uint32_t>(buffer.size()));
ss.append(std::string(buffer.begin(), buffer.begin() + bytes_read));
}
}
opcContainerCloseInputStream(part_stream);
return ss;
}
void write(const std::string &data)
{
auto name = get_uri().get_OriginalString();
auto name_pointer = name.c_str();
auto part_stream = opcContainerCreateOutputStream(container_, (xmlChar*)name_pointer, opcCompressionOption_t::OPC_COMPRESSIONOPTION_NORMAL);
std::stringstream ss(data);
std::array<xmlChar, 1024> buffer;
while(ss)
{
ss.get((char*)buffer.data(), 1024);
auto count = ss.gcount();
if(count > 0)
{
opcContainerWriteOutputStream(part_stream, buffer.data(), static_cast<opc_uint32_t>(count));
}
}
opcContainerCloseOutputStream(part_stream);
}
/// <summary>
/// Returns a value that indicates whether this part owns a relationship with a specified Id.
/// </summary>
bool relationship_exists(const std::string &id) const;
/// <summary>
/// Returns true if the given Id string is a valid relationship identifier.
/// </summary>
bool is_valid_xml_id(const std::string &id);
void operator=(const part_impl &other);
compression_option compression_option_;
std::string content_type_;
package &package_;
uri uri_;
opcContainer *container_;
};
part::part() : impl_(nullptr)
{
}
part::part(package &package, const uri &uri, opcContainer *container) : impl_(std::make_shared<part_impl>(package, uri, container))
{
}
std::string part::get_content_type() const
{
return "";
}
std::string part::read()
{
if(impl_.get() == nullptr)
{
return "";
}
return impl_->read();
}
void part::write(const std::string &data)
{
if(impl_.get() == nullptr)
{
return;
}
return impl_->write(data);
}
bool part::operator==(const part &comparand) const
{
return impl_.get() == comparand.impl_.get();
}
bool part::operator==(const nullptr_t &) const
{
return impl_.get() == nullptr;
}
} // namespace xlnt

105
source/packaging/part.h Normal file
View File

@ -0,0 +1,105 @@
#pragma once
#include <array>
#include <sstream>
#include <opc/opc.h>
#include "uri.h"
#include "compression_option.h"
#include "relationship.h"
#include "target_mode.h"
#include "file_mode.h"
#include "file_access.h"
namespace xlnt {
class part_impl;
/// <summary>
/// Represents a part that is stored in a ZipPackage.
/// </summary>
class part
{
public:
/// <summary>
/// Initializes a new instance of the part class with a specified parent Package, part URI, MIME content type, and compression_option.
/// </summary>
part(package &package, const uri &uri_part, const std::string &mime_type = "", compression_option compression = compression_option::NotCompressed);
part &operator=(const part &) = delete;
/// <summary>
/// gets the compression option of the part content stream.
/// </summary>
compression_option get_compression_option() const;
/// <summary>
/// gets the MIME type of the content stream.
/// </summary>
std::string get_content_type() const;
/// <summary>
/// gets the parent Package of the part.
/// </summary>
package &get_package() const;
/// <summary>
/// gets the URI of the part.
/// </summary>
uri get_uri() const;
/// <summary>
/// Creates a part-level relationship between this part to a specified target part or external resource.
/// </summary>
std::shared_ptr<relationship> create_relationship(const uri &target_uri, target_mode target_mode, const std::string &relationship_type);
/// <summary>
/// Deletes a specified part-level relationship.
/// </summary>
void delete_relationship(const std::string &id);
/// <summary>
/// Returns the relationship that has a specified Id.
/// </summary>
relationship get_relationship(const std::string &id);
/// <summary>
/// Returns a collection of all the relationships that are owned by this part.
/// </summary>
relationship_collection get_relationships();
/// <summary>
/// Returns a collection of the relationships that match a specified RelationshipType.
/// </summary>
relationship_collection get_relationship_by_type(const std::string &relationship_type);
/// <summary>
/// Returns all the content of this part.
/// </summary>
std::string read();
/// <summary>
/// Writes the given data to the part stream.
/// </summary>
void write(const std::string &data);
/// <summary>
/// Returns a value that indicates whether this part owns a relationship with a specified Id.
/// </summary>
bool relationship_exists(const std::string &id) const;
bool operator==(const part &comparand) const;
bool operator==(const nullptr_t &) const;
private:
friend class package_impl;
part();
part(package &package, const uri &uri, opcContainer *container);
std::shared_ptr<part_impl> impl_;
};
typedef std::vector<part> part_collection;
} // namespace xlnt

View File

@ -0,0 +1,66 @@
#pragma once
#include <memory>
#include <string>
#include <vector>
#include "target_mode.h"
#include "uri.h"
namespace xlnt {
class package;
/// <summary>
/// Represents an association between a source Package or part, and a target object which can be a part or external resource.
/// </summary>
class relationship
{
public:
/// <summary>
/// gets a string that identifies the relationship.
/// </summary>
std::string get_id() const { return id_; }
/// <summary>
/// gets the Package that contains this relationship.
/// </summary>
package &get_package() { return package_; }
/// <summary>
/// gets the qualified type name of the relationship.
/// </summary>
std::string get_relationship_type() const { return relationship_type_; }
/// <summary>
/// gets the URI of the package or part that owns the relationship.
/// </summary>
uri getsource_uri() const { return source_uri_; }
/// <summary>
/// gets a value that indicates whether the target of the relationship is or External to the Package.
/// </summary>
target_mode get_target_mode() const { return target_mode_; }
/// <summary>
/// gets the URI of the target resource of the relationship.
/// </summary>
uri get_target_uri() const { return target_uri_; }
private:
friend class package;
relationship(const std::string &id, package &package, const std::string &relationship_type_, uri source_uri, target_mode target_mode, uri target_uri);
relationship &operator=(const relationship &rhs) = delete;
std::string id_;
package &package_;
std::string relationship_type_;
uri source_uri_;
target_mode target_mode_;
uri target_uri_;
};
typedef std::vector<std::shared_ptr<relationship>> relationship_collection;
} // namespace xlnt

View File

@ -0,0 +1,20 @@
#pragma once
namespace xlnt {
/// <summary>
/// Specifies whether the target of a relationship is inside or outside the Package.
/// </summary>
enum class target_mode
{
/// <summary>
/// The relationship references a part that is inside the package.
/// </summary>
External,
/// <summary>
/// The relationship references a resource that is external to the package.
/// </summary>
Internal
};
} // namespace xlnt

397
source/packaging/uri.cpp Normal file
View File

@ -0,0 +1,397 @@
#include <sstream>
#include "uri.h"
namespace xlnt {
namespace {
#ifdef _WIN32
const char platform_path_separator = '\\';
#else
const char platform_path_separator = '/';
#endif
int get_DefaultPort(const std::string &scheme)
{
if(scheme == "ftp") return 21;
if(scheme == "sftp") return 22;
if(scheme == "ssh") return 22;
if(scheme == "telnet") return 23;
if(scheme == "smtp") return 25;
if(scheme == "dns") return 53;
if(scheme == "gopher") return 70;
if(scheme == "http") return 80;
if(scheme == "pop3") return 110;
if(scheme == "nntp") return 119;
if(scheme == "snmp") return 161;
if(scheme == "imap") return 143;
if(scheme == "irc") return 194;
if(scheme == "https") return 443;
if(scheme == "smtps") return 465;
return -1;
}
}
uri::uri(const std::string &uri_string, uri_kind uri_kind)
: original_string_(uri_string),
kind_(uri_kind)
{
Parse();
}
uri &uri::operator=(const uri &rhs)
{
original_string_ = rhs.original_string_;
kind_ = rhs.kind_;
Parse();
return *this;
}
bool uri::IsAbsoluteuri() const
{
if(kind_ == uri_kind::Absolute)
{
return true;
}
if(kind_ == uri_kind::Relative)
{
return false;
}
if(original_string_.size() == 0)
{
return false;
}
auto scheme_separator = std::find(original_string_.begin(), original_string_.end(), ':');
if(scheme_separator == original_string_.end())
{
return false;
}
if(original_string_[0] == '.')
{
return false;
}
return true;
}
void uri::Parse()
{
if(IsAbsoluteuri())
{
ParseAbsolute();
}
else
{
ParseRelative();
}
}
void uri::ParseAbsolute()
{
auto scheme_separator = std::find(original_string_.begin(), original_string_.end(), ':');
if(scheme_separator == original_string_.end())
{
throw std::runtime_error("absolute uri must contain a scheme followed by a colon");
}
scheme_ = std::string(original_string_.begin(), scheme_separator);
port_ = get_DefaultPort(scheme_);
std::string hier_part(scheme_separator + 1, original_string_.end());
auto query_separator = std::find(hier_part.begin(), hier_part.end(), '?');
if(query_separator != hier_part.end())
{
query_ = std::string(query_separator + 1, hier_part.end());
hier_part = std::string(hier_part.begin(), query_separator);
}
auto fragment_separator = std::find(hier_part.begin(), hier_part.end(), '#');
if(fragment_separator != hier_part.end())
{
fragment_ = std::string(fragment_separator + 1, hier_part.end());
hier_part = std::string(hier_part.begin(), fragment_separator);
}
else
{
fragment_separator = std::find(query_.begin(), query_.end(), '#');
if(fragment_separator != query_.end())
{
fragment_ = std::string(fragment_separator + 1, query_.end());
query_ = std::string(query_.begin(), fragment_separator);
}
}
if(hier_part.size() > 2 && hier_part[0] == '/' && hier_part[1] == '/')
{
auto path_separator = std::find(hier_part.begin() + 2, hier_part.end(), '/');
if(path_separator != hier_part.end())
{
authority_ = std::string(hier_part.begin() + 2, path_separator);
absolute_path_ = std::string(path_separator, hier_part.end());
if(absolute_path_[0] == '/')
{
if(absolute_path_[1] == '/')
{
throw std::runtime_error("path can't start with //");
}
}
}
else
{
authority_ = hier_part.substr(2);
absolute_path_ = "";
}
ParseAuthority();
is_file_ = scheme_ == "file";
char abs_path_separator = absolute_path_.find('/') != std::string::npos ? '/' : '\\';
if(is_file_)
{
local_path_ = std::string(2, platform_path_separator) + authority_;
}
if(absolute_path_.size() > 0)
{
std::stringstream ss(absolute_path_);
std::string part;
while(std::getline(ss, part, abs_path_separator))
{
if(segments_.size() > 0)
{
if(is_file_)
{
segments_.back().append(1, platform_path_separator);
local_path_.append(1, platform_path_separator);
}
else
{
segments_.back().append(1, abs_path_separator);
local_path_.append(1, abs_path_separator);
}
}
segments_.push_back(part);
local_path_.append(part);
}
}
user_escaped_ = false;
is_unc_ = is_file_ && host_.size() > 0;
is_default_port_ = get_DefaultPort(scheme_) == port_;
is_loopback_ = host_ == "127.0.0.1" || host_ == "localhost" || host_ == "loopback" || host_.size() == 0;
path_and_query_ = absolute_path_ + "?" + query_;
absolute_uri_ = scheme_ + "://";
if(user_info_.size() > 0)
{
absolute_uri_ += user_info_ + "@";
}
absolute_uri_ += host_;
if(!is_default_port_)
{
absolute_uri_ += ":" + std::to_string(port_);
}
absolute_uri_ += absolute_path_;
if(query_.size() > 0)
{
absolute_uri_ += "?" + query_;
}
if(fragment_.size() > 0)
{
absolute_uri_ += "#" + fragment_;
}
}
}
void uri::ParseRelative()
{
absolute_path_ = "";
absolute_uri_ = "";
authority_ = "";
dns_safe_host_ = "";
fragment_ = "";
host_ = "";
host_name_type_ = uri_host_name_type::Unknown;
is_default_port_ = false;
is_file_ = false;
is_loopback_ = false;
is_unc_ = false;
local_path_ = "";
path_and_query_ = "";
port_ = -1;
query_ = "";
scheme_ = "";
user_escaped_ = false;
user_info_ = "";
}
void uri::ParseAuthority()
{
if(authority_.size() == 0)
{
return;
}
host_ = authority_;
auto user_info_separator = std::find(host_.begin(), host_.end(), '@');
if(user_info_separator != host_.end())
{
user_info_ = std::string(host_.begin(), user_info_separator);
host_ = std::string(user_info_separator + 1, host_.end());
}
auto port_separator_index = host_.find_last_of(':');
if(port_separator_index != std::string::npos)
{
port_ = std::stoi(host_.substr(port_separator_index + 1));
host_ = host_.substr(0, port_separator_index);
}
dns_safe_host_ = host_;
if(host_.find(':') == std::string::npos)
{
host_name_type_ = uri_host_name_type::Dns;
}
else
{
host_name_type_ = uri_host_name_type::IPv4;
}
}
std::string uri::get_AbsolutePath() const
{
ThrowIfNotAbsolute();
return absolute_path_;
}
std::string uri::get_Absoluteuri() const
{
ThrowIfNotAbsolute();
return absolute_uri_;
}
std::string uri::get_Authority() const
{
ThrowIfNotAbsolute();
return authority_;
}
std::string uri::get_DnsSafeHost() const
{
ThrowIfNotAbsolute();
return dns_safe_host_;
}
std::string uri::get_Fragment() const
{
ThrowIfNotAbsolute();
return fragment_;
}
std::string uri::get_Host() const
{
ThrowIfNotAbsolute();
return host_;
}
uri_host_name_type uri::get_HostNameType() const
{
ThrowIfNotAbsolute();
return host_name_type_;
}
bool uri::IsDefaultPort() const
{
ThrowIfNotAbsolute();
return is_default_port_;
}
bool uri::IsFile() const
{
ThrowIfNotAbsolute();
return is_file_;
}
bool uri::IsLoopback() const
{
ThrowIfNotAbsolute();
return is_loopback_;
}
bool uri::IsUnc() const
{
ThrowIfNotAbsolute();
return is_unc_;
}
std::string uri::get_LocalPath() const
{
ThrowIfNotAbsolute();
return local_path_;
}
std::string uri::get_OriginalString() const
{
return original_string_;
}
std::string uri::get_PathAndQuery() const
{
ThrowIfNotAbsolute();
return path_and_query_;
}
int uri::get_Port() const
{
ThrowIfNotAbsolute();
return port_;
}
std::string uri::get_Query() const
{
ThrowIfNotAbsolute();
return query_;
}
std::string uri::get_Scheme() const
{
ThrowIfNotAbsolute();
return scheme_;
}
std::vector<std::string> uri::get_Segments() const
{
ThrowIfNotAbsolute();
return segments_;
}
bool uri::get_UserEscaped() const
{
return user_escaped_;
}
std::string uri::get_UserInfo() const
{
ThrowIfNotAbsolute();
return user_info_;
}
void uri::ThrowIfNotAbsolute() const
{
if(!IsAbsoluteuri())
{
throw std::runtime_error("InvalidOperationException: This instance represents a relative URI, and this property is valid only for absolute URIs.");
}
}
} // namespace xlnt

485
source/packaging/uri.h Normal file
View File

@ -0,0 +1,485 @@
#pragma once
#include <string>
#include <vector>
namespace xlnt {
/// <summary>
/// Defines the kinds of uris for the uri::IsWellFormeduriString(std::tring, uri_kind) and several other uri methods.
/// </summary>
enum class uri_kind
{
/// <summary>
/// The uri is an absolute uri.
/// </summary>
Absolute,
/// <summary>
/// The uri is a relative uri.
/// </summary>
Relative,
/// <summary>
/// The kind of the uri is indeterminate.
/// </summary>
RelativeOrAbsolute
};
/// <summary>
/// Defines host name types for the uri.CheckHostName method.
/// </summary>
enum class uri_host_name_type
{
/// <summary>
/// The host is set, but the type cannot be determined.
/// </summary>
Basic,
/// <summary>
/// The host name is a domain name system (DNS) style host name.
/// </summary>
Dns,
/// <summary>
/// The host name is an Internet Protocol (IP) version 4 host address.
/// </summary>
IPv4,
/// <summary>
/// The host name is an Internet Protocol (IP) version 6 host address.
/// </summary>
IPv6,
/// <summary>
/// The type of the host name is not supplied.
/// </summary>
Unknown
};
/// <summary>
/// Specifies the parts of a uri.
/// </summary>
enum class uri_components
{
/// <summary>
/// The Scheme, UserInfo, Host, Port, LocalPath, Query, and Fragment data.
/// </summary>
Absoluteuri,
/// <summary>
/// The Fragment data.
/// </summary>
Fragment,
/// <summary>
/// The Host data.
/// </summary>
Host,
/// <summary>
/// The Host and Port data. If no port data is in the uri and a default port has been assigned to the Scheme, the default port is returned. If there is no default port, -1 is returned.
/// </summary>
HostAndPort,
/// <summary>
/// The Scheme, Host, Port, LocalPath, and Query data.
/// </summary>
HttpRequesturi,
/// <summary>
/// Specifies that the delimiter should be included.
/// </summary>
KeepDelimiter,
/// <summary>
/// The normalized form of the Host.
/// </summary>
NormalizedHost,
/// <summary>
/// The LocalPath data.
/// </summary>
Path,
/// <summary>
/// The LocalPath and Query data. Also see PathAndQuery.
/// </summary>
PathAndQuery,
/// <summary>
/// The Port data.
/// </summary>
Port,
/// <summary>
/// The Query data.
/// </summary>
Query,
/// <summary>
/// The Scheme data.
/// </summary>
Scheme,
/// <summary>
/// The Scheme, Host, and Port data.
/// </summary>
SchemeAndServer,
/// <summary>
/// The Port data. If no port data is in the uri and a default port has been assigned to the Scheme, the default port is returned. If there is no default port, -1 is returned.
/// </summary>
StrongPort,
/// <summary>
/// The UserInfo data.
/// </summary>
UserInfo
};
/// <summary>
/// Controls how URI information is escaped.
/// </summary>
enum class uri_format
{
/// <summary>
/// Characters that have a reserved meaning in the requested URI components remain escaped. All others are not escaped. See Remarks.
/// </summary>
SafeUnescaped,
/// <summary>
/// No escaping is performed.
/// </summary>
Unescaped,
/// <summary>
/// Escaping is performed according to the rules in RFC 2396.
/// </summary>
uriEscaped
};
/// <summary>
/// Specifies the culture, case, and sort rules to be used by certain overloads of the String.Compare and String._equals methods
/// </summary>
enum class string_comparison
{
/// <summary>
/// Compare strings using culture-sensitive sort rules and the current culture.
/// </summary>
CurrentCulture,
/// <summary>
/// Compare strings using culture-sensitive sort rules, the current culture, and ignoring the case of the strings being compared.
/// </summary>
CurrentCultureIgnoreCase,
/// <summary>
/// Compare strings using culture-sensitive sort rules and the invariant culture.
/// </summary>
InvariantCulture,
/// <summary>
/// Compare strings using culture-sensitive sort rules, the invariant culture, and ignoring the case of the strings being compared.
/// </summary>
InvariantCultureIgnoreCase,
/// <summary>
/// Compare strings using ordinal sort rules.
/// </summary>
Ordinal,
/// <summary>
/// Compare strings using ordinal sort rules and ignoring the case of the strings being compared.
/// </summary>
OrdinalIgnoreCase
};
/// <summary>
/// Defines the parts of a URI for the uri::get_LeftPart method.
/// </summary>
enum class uri_partial
{
/// <summary>
/// The scheme and authority segments of the URI.
/// </summary>
Authority,
/// <summary>
/// The scheme, authority, and path segments of the URI.
/// </summary>
Path,
/// <summary>
/// The scheme, authority, path, and query segments of the URI.
/// </summary>
Query,
/// <summary>
/// The scheme segment of the URI.
/// </summary>
Scheme
};
/// <summary>
/// Provides an object representation of a uniform resource identifier (URI) and easy access to the parts of the URI.
/// </summary>
class uri
{
public:
/// <summary>
/// Determines whether the specified host name is a valid DNS name.
/// </summary>
static uri_host_name_type CheckHostName(const std::string &name);
/// <summary>
/// Determines whether the specified scheme name is valid.
/// </summary>
static bool CheckSchemeName(const std::string &scheme_name);
/// <summary>
/// Compares the specified parts of two URIs using the specified comparison rules.
/// </summary>
static int Compare(const uri &uri1, const uri &uri2, const uri_components &parts_to_compare,
uri_format compare_format, string_comparison comparison_type);
/// <summary>
/// Converts a string to its escaped representation.
/// </summary>
static std::string EscapeDataString(const std::string &string_to_escape);
/// <summary>
/// Converts a URI string to its escaped representation.
/// </summary>
static std::string EscapeuriString(const std::string &string_to_escape);
/// <summary>
/// gets the decimal value of a hexadecimal digit.
/// </summary>
static int FromHex(char digit);
/// <summary>
/// Converts a specified character into its hexadecimal equivalent.
/// </summary>
static std::string HexEscape(char character);
/// <summary>
/// Converts a specified hexadecimal representation of a character to the character.
/// </summary>
static char HexUnescape(const std::string &pattern, int &index);
/// <summary>
/// Determines whether a specified character is a valid hexadecimal digit.
/// </summary>
static bool IsHexDigit(char character);
/// <summary>
/// Determines whether a character in a string is hexadecimal encoded.
/// </summary>
static bool IsHexEncoding(const std::string &pattern, int index);
/// <summary>
/// Indicates whether the string is well-formed by attempting to construct a URI with the string and ensures that the string does not require further escaping.
/// </summary>
static bool IsWellFormeduriString(const std::string &uri_string, uri_kind uri_kind);
/// <summary>
/// Creates a new uri using the specified String instance and a uri_kind.
/// </summary>
static bool TryCreate(const std::string &uri_string, uri_kind uri_kind, uri &result);
/// <summary>
/// Creates a new uri using the specified base and relative String instances.
/// </summary>
static bool TryCreate(const uri &base_uri, const std::string &relative_uri, uri &result);
/// <summary>
/// Creates a new uri using the specified base and relative uri instances.
/// </summary>
static bool TryCreate(const uri &base_uri, const uri &relative_uri, uri &result);
/// <summary>
/// Converts a string to its unescaped representation.
/// </summary>
static std::string UnescapeDataString(const std::string &string_to_unescape);
/// <summary>
/// Initializes a new instance of the uri class with the specified URI. This constructor allows you to specify if the URI string is a relative URI, absolute URI, or is indeterminate.
/// </summary>
uri(const std::string &uri_string, uri_kind uri_kind = uri_kind::Absolute);
/// <summary>
/// Initializes a new instance of the uri class based on the specified base URI and relative URI string.
/// </summary>
uri(const uri &base_uri, const std::string &relative_uri);
/// <summary>
/// Initializes a new instance of the uri class based on the combination of a specified base uri instance and a relative uri instance.
/// </summary>
uri(const uri &base_uri, const uri &relative_uri);
/// <summary>
///
/// </summary>
uri &operator=(const uri &);
/// <summary>
/// gets the absolute path of the URI.
/// </summary>
std::string get_AbsolutePath() const;
/// <summary>
/// gets the absolute URI.
/// </summary>
std::string get_Absoluteuri() const;
/// <summary>
/// gets the Domain Name System (DNS) host name or IP address and the port number for a server.
/// </summary>
std::string get_Authority() const;
/// <summary>
/// gets an unescaped host name that is safe to use for DNS resolution.
/// </summary>
std::string get_DnsSafeHost() const;
/// <summary>
/// gets the escaped URI fragment.
/// </summary>
std::string get_Fragment() const;
/// <summary>
/// gets the host component of this instance.
/// </summary>
std::string get_Host() const;
/// <summary>
/// gets the type of the host name specified in the URI.
/// </summary>
uri_host_name_type get_HostNameType() const;
/// <summary>
/// gets whether the uri instance is absolute.
/// </summary>
bool IsAbsoluteuri() const;
/// <summary>
/// gets whether the port value of the URI is the default for this scheme.
/// </summary>
bool IsDefaultPort() const;
/// <summary>
/// gets a value indicating whether the specified uri is a file URI.
/// </summary>
bool IsFile() const;
/// <summary>
/// gets whether the specified uri references the local host.
/// </summary>
bool IsLoopback() const;
/// <summary>
/// gets whether the specified uri is a universal naming convention (UNC) path.
/// </summary>
bool IsUnc() const;
/// <summary>
/// gets a local operating-system representation of a file name.
/// </summary>
std::string get_LocalPath() const;
/// <summary>
/// gets the original URI string that was passed to the uri constructor.
/// </summary>
std::string get_OriginalString() const;
/// <summary>
/// gets the AbsolutePath and Query properties separated by a question mark (?).
/// </summary>
std::string get_PathAndQuery() const;
/// <summary>
/// gets the port number of this URI.
/// </summary>
int get_Port() const;
/// <summary>
/// gets any query information included in the specified URI.
/// </summary>
std::string get_Query() const;
/// <summary>
/// gets the scheme name for this URI.
/// </summary>
std::string get_Scheme() const;
/// <summary>
/// gets an array containing the path segments that make up the specified URI.
/// </summary>
std::vector<std::string> get_Segments() const;
/// <summary>
/// Indicates that the URI string was completely escaped before the uri instance was created.
/// </summary>
bool get_UserEscaped() const;
/// <summary>
/// gets the user name, password, or other user-specific information associated with the specified URI.
/// </summary>
std::string get_UserInfo() const;
/// <summary>
/// Compares two uri instances for equality.
/// </summary>
bool Equals(const uri &comparand);
/// <summary>
/// gets the specified components of the current instance using the specified escaping for special characters.
/// </summary>
std::string get_Components(uri_components components, uri_format format);
/// <summary>
/// gets the specified portion of a uri instance.
/// </summary>
std::string get_LeftPart(uri_partial part);
/// <summary>
/// Determines whether the current uri instance is a base of the specified uri instance.
/// </summary>
bool IsBaseOf(const uri &uri);
/// <summary>
/// Indicates whether the string used to construct this uri was well-formed and is not required to be further escaped.
/// </summary>
bool IsWellFormedOriginalString();
/// <summary>
/// Determines the difference between two uri instances.
/// </summary>
uri MakeRelativeuri(const uri &uri);
private:
void Parse();
void ParseAbsolute();
void ParseRelative();
void ParseAuthority();
void ThrowIfNotAbsolute() const;
std::string original_string_;
uri_kind kind_;
std::string absolute_path_;
std::string absolute_uri_;
std::string authority_;
std::string dns_safe_host_;
std::string fragment_;
std::string host_;
uri_host_name_type host_name_type_;
bool is_default_port_;
bool is_file_;
bool is_unc_;
bool is_loopback_;
std::string local_path_;
std::string path_and_query_;
int port_;
std::string query_;
std::string scheme_;
std::vector<std::string> segments_;
bool user_escaped_;
std::string user_info_;
};
} // namespace xlnt

10
source/reader/reader.cpp Normal file
View File

@ -0,0 +1,10 @@
#include "reader.h"
namespace xlnt {
workbook reader::load_workbook(const std::string &/*filename*/)
{
return workbook();
}
} // namespace xlnt

26
source/shared/cell.cpp Normal file
View File

@ -0,0 +1,26 @@
#include "cell.h"
namespace xlnt {
class cell_impl
{
public:
variant value;
};
cell::cell() : impl_(nullptr)
{
}
variant cell::value()
{
if(impl_ == nullptr)
{
return variant();
}
return impl_->value;
}
} // namespace xlnt

32
source/shared/range.cpp Normal file
View File

@ -0,0 +1,32 @@
#include "range.h"
namespace xlnt {
class range_impl
{
public:
cell cell(const std::string &address)
{
return cells_[address];
}
private:
std::unordered_map<std::string, class cell> cells_;
};
range::range() : impl_(nullptr)
{
}
cell range::cell(const std::string &address)
{
if(impl_ == nullptr)
{
return class cell();
}
return impl_->cell(address);
}
} // namespace xlnt

View File

@ -0,0 +1,31 @@
#include "workbook.h"
namespace xlnt {
class workbook_impl
{
public:
worksheet get_sheet_by_name(const std::string &name)
{
return worksheets_[name];
}
std::unordered_map<std::string, worksheet> worksheets_;
};
workbook::workbook() : impl_(nullptr)
{
}
worksheet workbook::get_sheet_by_name(const std::string &name)
{
if(impl_ == nullptr)
{
return worksheet();
}
return impl_->get_sheet_by_name(name);
}
} // namespace xlnt

View File

@ -0,0 +1,10 @@
#include "worksheet.h"
namespace xlnt {
worksheet::worksheet() : impl_(nullptr)
{
}
} // namespace xlnt

View File

@ -0,0 +1,58 @@
#pragma once
#include <iostream>
#include <cxxtest/TestSuite.h>
#include "../../misc/nullable.h"
class NullableTestSuite : public CxxTest::TestSuite
{
public:
NullableTestSuite() : integer_non_null_5(5), double_non_null_5(5.0), double_non_null_6(6.0)
{
}
void test_has_value()
{
TS_ASSERT(!integer_null.has_value())
TS_ASSERT(integer_non_null_5.has_value())
}
void test_get_value()
{
TS_ASSERT_THROWS_ANYTHING(integer_null.get_value())
TS_ASSERT_THROWS_NOTHING(integer_non_null_5.get_value())
TS_ASSERT_EQUALS(integer_non_null_5.get_value(), 5)
}
void test_equality()
{
TS_ASSERT_EQUALS(integer_null, integer_null_2)
TS_ASSERT_DIFFERS(integer_null, integer_non_null_5)
TS_ASSERT_DIFFERS(double_non_null_5, double_non_null_6)
}
void test_assignment()
{
xlnt::nullable<double> double_non_null_6_assigned;
double_non_null_6_assigned = double_non_null_6;
TS_ASSERT(double_non_null_6_assigned.has_value())
TS_ASSERT_EQUALS(double_non_null_6_assigned.get_value(), 6.0)
}
void test_copy_constructor()
{
xlnt::nullable<int> integer_non_null_5_copy(integer_non_null_5);
TS_ASSERT(integer_non_null_5_copy.has_value())
TS_ASSERT_EQUALS(integer_non_null_5_copy.get_value(), 5)
}
private:
xlnt::nullable<int> integer_null;
xlnt::nullable<int> integer_null_2;
xlnt::nullable<int> integer_non_null_5;
xlnt::nullable<double> double_null;
xlnt::nullable<double> double_non_null_5;
xlnt::nullable<double> double_non_null_6;
};

View File

@ -0,0 +1,81 @@
#pragma once
#include <cxxtest/TestSuite.h>
#include "../../packaging/File.h"
#include "../../misc/pugixml.hpp"
#include "../../packaging/package.h"
class ZipPackageTestSuite : public CxxTest::TestSuite
{
public:
ZipPackageTestSuite()
{
xlnt::file::copy("../../source/tests/packaging/test.zip", "../../source/tests/packaging/a.zip", true);
}
void test_read_text()
{
auto package = xlnt::package::open("../../source/tests/packaging/a.zip", xlnt::file_mode::Open, xlnt::file_access::ReadWrite);
TS_ASSERT_DIFFERS(package, nullptr);
auto part_1 = package.get_part(xlnt::uri("a.txt", xlnt::uri_kind::Relative));
TS_ASSERT_DIFFERS(part_1, nullptr);
auto part_1_data = part_1.read();
TS_ASSERT_EQUALS(part_1_data, "a.txt");
}
void test_write_text()
{
{
auto package = xlnt::package::open("../../source/tests/packaging/a.zip", xlnt::file_mode::Open, xlnt::file_access::ReadWrite);
TS_ASSERT_DIFFERS(package, nullptr);
auto part_1 = package.get_part(xlnt::uri("a.txt", xlnt::uri_kind::Relative));
TS_ASSERT_DIFFERS(part_1, nullptr);
part_1.write("something else");
}
{
auto package = xlnt::package::open("../../source/tests/packaging/a.zip", xlnt::file_mode::Open, xlnt::file_access::ReadWrite);
TS_ASSERT_DIFFERS(package, nullptr);
auto part_1 = package.get_part(xlnt::uri("a.txt", xlnt::uri_kind::Relative));
TS_ASSERT_DIFFERS(part_1, nullptr);
auto part_1_data = part_1.read();
TS_ASSERT_EQUALS(part_1_data, "something else");
}
}
void test_read_xml()
{
auto package = xlnt::package::open("../../source/tests/packaging/a.zip", xlnt::file_mode::Open, xlnt::file_access::ReadWrite);
TS_ASSERT_DIFFERS(package, nullptr);
auto part_2 = package.get_part(xlnt::uri("a.xml", xlnt::uri_kind::Relative));
TS_ASSERT_DIFFERS(part_2, nullptr);
auto part_2_data = part_2.read();
TS_ASSERT_DIFFERS(part_2_data, "");
pugi::xml_document part_2_doc;
part_2_doc.load(part_2_data.c_str());
auto root_element = part_2_doc.child("root");
TS_ASSERT_DIFFERS(root_element, nullptr)
auto child_element = root_element.child("child");
TS_ASSERT_DIFFERS(child_element, nullptr)
TS_ASSERT_EQUALS(std::string(child_element.attribute("attribute").as_string()), "attribute")
auto element_element = root_element.child("element");
TS_ASSERT_DIFFERS(element_element, nullptr)
TS_ASSERT_EQUALS(std::string(element_element.text().as_string()), "Text")
}
};

View File

@ -0,0 +1,117 @@
#pragma once
#include <cxxtest/TestSuite.h>
#include "../../source/Packaging/uri.h"
class uriTestSuite : public CxxTest::TestSuite
{
public:
uriTestSuite() : uri(complex_url)
{
}
void test_absolute_path()
{
TS_ASSERT_EQUALS(uri.get_AbsolutePath(), "/tfussell/EPPlusPlus.git");
}
void test_absolute_uri()
{
TS_ASSERT_EQUALS(uri.get_Absoluteuri(), complex_url);
}
void test_authority()
{
TS_ASSERT_EQUALS(uri.get_Authority(), "thomas:password@github.com:71");
}
void test_dns_safe_host()
{
TS_ASSERT_EQUALS(uri.get_DnsSafeHost(), "github.com");
}
void test_fragment()
{
TS_ASSERT_EQUALS(uri.get_Fragment(), "abc");
}
void test_get_host()
{
TS_ASSERT_EQUALS(uri.get_Host(), "github.com");
}
void test_host_name_type()
{
TS_ASSERT_EQUALS(uri.get_HostNameType(), xlnt::uri_host_name_type::Dns);
}
void test_is_absolute_uri()
{
TS_ASSERT_EQUALS(uri.IsAbsoluteuri(), true);
}
void test_default_port()
{
TS_ASSERT_EQUALS(uri.IsDefaultPort(), false);
}
void test_is_file()
{
TS_ASSERT_EQUALS(uri.IsFile(), false);
}
void test_is_loopback()
{
TS_ASSERT_EQUALS(uri.IsLoopback(), false);
}
void test_is_unc()
{
TS_ASSERT_EQUALS(uri.IsUnc(), false);
}
void test_local_path()
{
TS_ASSERT_EQUALS(uri.get_LocalPath(), "/tfussell/EPPlusPlus.git");
}
void test_original_string()
{
TS_ASSERT_EQUALS(uri.get_OriginalString(), complex_url);
}
void test_path_and_query()
{
TS_ASSERT_EQUALS(uri.get_PathAndQuery(), "/tfussell/EPPlusPlus.git?a=1&b=2");
}
void test_port()
{
TS_ASSERT_EQUALS(uri.get_Port(), 71);
}
void test_query()
{
TS_ASSERT_EQUALS(uri.get_Query(), "a=1&b=2");
}
void test_scheme()
{
TS_ASSERT_EQUALS(uri.get_Scheme(), "https");
}
void test_user_escaped()
{
TS_ASSERT_EQUALS(uri.get_UserEscaped(), false);
}
void test_user_info()
{
TS_ASSERT_EQUALS(uri.get_UserInfo(), "thomas:password");
}
private:
const std::string complex_url = "https://thomas:password@github.com:71/tfussell/EPPlusPlus.git?a=1&b=2#abc";
xlnt::uri uri;
};

View File

@ -0,0 +1 @@
a.txt

View File

@ -0,0 +1,4 @@
<root>
<child attribute="attribute" />
<element>Text</element>
</root>

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,214 @@
/* Generated file, do not edit */
#ifndef CXXTEST_RUNNING
#define CXXTEST_RUNNING
#endif
#define _CXXTEST_HAVE_STD
#define _CXXTEST_HAVE_EH
#include <cxxtest/TestListener.h>
#include <cxxtest/TestTracker.h>
#include <cxxtest/TestRunner.h>
#include <cxxtest/RealDescriptions.h>
#include <cxxtest/TestMain.h>
#include <cxxtest/ParenPrinter.h>
int main( int argc, char *argv[] ) {
int status;
CxxTest::ParenPrinter tmp;
CxxTest::RealWorldDescription::_worldName = "cxxtest";
status = CxxTest::Main< CxxTest::ParenPrinter >( tmp, argc, argv );
return status;
}
bool suite_NullableTestSuite_init = false;
#include "C:\Users\taf656\Development\xlnt\source\tests\packaging\NullableTestSuite.h"
static NullableTestSuite suite_NullableTestSuite;
static CxxTest::List Tests_NullableTestSuite = { 0, 0 };
CxxTest::StaticSuiteDescription suiteDescription_NullableTestSuite( "../../source/tests/packaging/NullableTestSuite.h", 8, "NullableTestSuite", suite_NullableTestSuite, Tests_NullableTestSuite );
static class TestDescription_suite_NullableTestSuite_test_has_value : public CxxTest::RealTestDescription {
public:
TestDescription_suite_NullableTestSuite_test_has_value() : CxxTest::RealTestDescription( Tests_NullableTestSuite, suiteDescription_NullableTestSuite, 16, "test_has_value" ) {}
void runTest() { suite_NullableTestSuite.test_has_value(); }
} testDescription_suite_NullableTestSuite_test_has_value;
static class TestDescription_suite_NullableTestSuite_test_get_value : public CxxTest::RealTestDescription {
public:
TestDescription_suite_NullableTestSuite_test_get_value() : CxxTest::RealTestDescription( Tests_NullableTestSuite, suiteDescription_NullableTestSuite, 22, "test_get_value" ) {}
void runTest() { suite_NullableTestSuite.test_get_value(); }
} testDescription_suite_NullableTestSuite_test_get_value;
static class TestDescription_suite_NullableTestSuite_test_equality : public CxxTest::RealTestDescription {
public:
TestDescription_suite_NullableTestSuite_test_equality() : CxxTest::RealTestDescription( Tests_NullableTestSuite, suiteDescription_NullableTestSuite, 29, "test_equality" ) {}
void runTest() { suite_NullableTestSuite.test_equality(); }
} testDescription_suite_NullableTestSuite_test_equality;
static class TestDescription_suite_NullableTestSuite_test_assignment : public CxxTest::RealTestDescription {
public:
TestDescription_suite_NullableTestSuite_test_assignment() : CxxTest::RealTestDescription( Tests_NullableTestSuite, suiteDescription_NullableTestSuite, 36, "test_assignment" ) {}
void runTest() { suite_NullableTestSuite.test_assignment(); }
} testDescription_suite_NullableTestSuite_test_assignment;
static class TestDescription_suite_NullableTestSuite_test_copy_constructor : public CxxTest::RealTestDescription {
public:
TestDescription_suite_NullableTestSuite_test_copy_constructor() : CxxTest::RealTestDescription( Tests_NullableTestSuite, suiteDescription_NullableTestSuite, 44, "test_copy_constructor" ) {}
void runTest() { suite_NullableTestSuite.test_copy_constructor(); }
} testDescription_suite_NullableTestSuite_test_copy_constructor;
#include "C:\Users\taf656\Development\xlnt\source\tests\packaging\PackageTestSuite.h"
static ZipPackageTestSuite suite_ZipPackageTestSuite;
static CxxTest::List Tests_ZipPackageTestSuite = { 0, 0 };
CxxTest::StaticSuiteDescription suiteDescription_ZipPackageTestSuite( "../../source/tests/packaging/PackageTestSuite.h", 9, "ZipPackageTestSuite", suite_ZipPackageTestSuite, Tests_ZipPackageTestSuite );
static class TestDescription_suite_ZipPackageTestSuite_test_read_text : public CxxTest::RealTestDescription {
public:
TestDescription_suite_ZipPackageTestSuite_test_read_text() : CxxTest::RealTestDescription( Tests_ZipPackageTestSuite, suiteDescription_ZipPackageTestSuite, 17, "test_read_text" ) {}
void runTest() { suite_ZipPackageTestSuite.test_read_text(); }
} testDescription_suite_ZipPackageTestSuite_test_read_text;
static class TestDescription_suite_ZipPackageTestSuite_test_write_text : public CxxTest::RealTestDescription {
public:
TestDescription_suite_ZipPackageTestSuite_test_write_text() : CxxTest::RealTestDescription( Tests_ZipPackageTestSuite, suiteDescription_ZipPackageTestSuite, 29, "test_write_text" ) {}
void runTest() { suite_ZipPackageTestSuite.test_write_text(); }
} testDescription_suite_ZipPackageTestSuite_test_write_text;
static class TestDescription_suite_ZipPackageTestSuite_test_read_xml : public CxxTest::RealTestDescription {
public:
TestDescription_suite_ZipPackageTestSuite_test_read_xml() : CxxTest::RealTestDescription( Tests_ZipPackageTestSuite, suiteDescription_ZipPackageTestSuite, 54, "test_read_xml" ) {}
void runTest() { suite_ZipPackageTestSuite.test_read_xml(); }
} testDescription_suite_ZipPackageTestSuite_test_read_xml;
#include "C:\Users\taf656\Development\xlnt\source\tests\packaging\UriTestSuite.h"
static uriTestSuite suite_uriTestSuite;
static CxxTest::List Tests_uriTestSuite = { 0, 0 };
CxxTest::StaticSuiteDescription suiteDescription_uriTestSuite( "../../source/tests/packaging/UriTestSuite.h", 6, "uriTestSuite", suite_uriTestSuite, Tests_uriTestSuite );
static class TestDescription_suite_uriTestSuite_test_absolute_path : public CxxTest::RealTestDescription {
public:
TestDescription_suite_uriTestSuite_test_absolute_path() : CxxTest::RealTestDescription( Tests_uriTestSuite, suiteDescription_uriTestSuite, 14, "test_absolute_path" ) {}
void runTest() { suite_uriTestSuite.test_absolute_path(); }
} testDescription_suite_uriTestSuite_test_absolute_path;
static class TestDescription_suite_uriTestSuite_test_absolute_uri : public CxxTest::RealTestDescription {
public:
TestDescription_suite_uriTestSuite_test_absolute_uri() : CxxTest::RealTestDescription( Tests_uriTestSuite, suiteDescription_uriTestSuite, 19, "test_absolute_uri" ) {}
void runTest() { suite_uriTestSuite.test_absolute_uri(); }
} testDescription_suite_uriTestSuite_test_absolute_uri;
static class TestDescription_suite_uriTestSuite_test_authority : public CxxTest::RealTestDescription {
public:
TestDescription_suite_uriTestSuite_test_authority() : CxxTest::RealTestDescription( Tests_uriTestSuite, suiteDescription_uriTestSuite, 24, "test_authority" ) {}
void runTest() { suite_uriTestSuite.test_authority(); }
} testDescription_suite_uriTestSuite_test_authority;
static class TestDescription_suite_uriTestSuite_test_dns_safe_host : public CxxTest::RealTestDescription {
public:
TestDescription_suite_uriTestSuite_test_dns_safe_host() : CxxTest::RealTestDescription( Tests_uriTestSuite, suiteDescription_uriTestSuite, 29, "test_dns_safe_host" ) {}
void runTest() { suite_uriTestSuite.test_dns_safe_host(); }
} testDescription_suite_uriTestSuite_test_dns_safe_host;
static class TestDescription_suite_uriTestSuite_test_fragment : public CxxTest::RealTestDescription {
public:
TestDescription_suite_uriTestSuite_test_fragment() : CxxTest::RealTestDescription( Tests_uriTestSuite, suiteDescription_uriTestSuite, 34, "test_fragment" ) {}
void runTest() { suite_uriTestSuite.test_fragment(); }
} testDescription_suite_uriTestSuite_test_fragment;
static class TestDescription_suite_uriTestSuite_test_get_host : public CxxTest::RealTestDescription {
public:
TestDescription_suite_uriTestSuite_test_get_host() : CxxTest::RealTestDescription( Tests_uriTestSuite, suiteDescription_uriTestSuite, 39, "test_get_host" ) {}
void runTest() { suite_uriTestSuite.test_get_host(); }
} testDescription_suite_uriTestSuite_test_get_host;
static class TestDescription_suite_uriTestSuite_test_host_name_type : public CxxTest::RealTestDescription {
public:
TestDescription_suite_uriTestSuite_test_host_name_type() : CxxTest::RealTestDescription( Tests_uriTestSuite, suiteDescription_uriTestSuite, 44, "test_host_name_type" ) {}
void runTest() { suite_uriTestSuite.test_host_name_type(); }
} testDescription_suite_uriTestSuite_test_host_name_type;
static class TestDescription_suite_uriTestSuite_test_is_absolute_uri : public CxxTest::RealTestDescription {
public:
TestDescription_suite_uriTestSuite_test_is_absolute_uri() : CxxTest::RealTestDescription( Tests_uriTestSuite, suiteDescription_uriTestSuite, 49, "test_is_absolute_uri" ) {}
void runTest() { suite_uriTestSuite.test_is_absolute_uri(); }
} testDescription_suite_uriTestSuite_test_is_absolute_uri;
static class TestDescription_suite_uriTestSuite_test_default_port : public CxxTest::RealTestDescription {
public:
TestDescription_suite_uriTestSuite_test_default_port() : CxxTest::RealTestDescription( Tests_uriTestSuite, suiteDescription_uriTestSuite, 54, "test_default_port" ) {}
void runTest() { suite_uriTestSuite.test_default_port(); }
} testDescription_suite_uriTestSuite_test_default_port;
static class TestDescription_suite_uriTestSuite_test_is_file : public CxxTest::RealTestDescription {
public:
TestDescription_suite_uriTestSuite_test_is_file() : CxxTest::RealTestDescription( Tests_uriTestSuite, suiteDescription_uriTestSuite, 59, "test_is_file" ) {}
void runTest() { suite_uriTestSuite.test_is_file(); }
} testDescription_suite_uriTestSuite_test_is_file;
static class TestDescription_suite_uriTestSuite_test_is_loopback : public CxxTest::RealTestDescription {
public:
TestDescription_suite_uriTestSuite_test_is_loopback() : CxxTest::RealTestDescription( Tests_uriTestSuite, suiteDescription_uriTestSuite, 64, "test_is_loopback" ) {}
void runTest() { suite_uriTestSuite.test_is_loopback(); }
} testDescription_suite_uriTestSuite_test_is_loopback;
static class TestDescription_suite_uriTestSuite_test_is_unc : public CxxTest::RealTestDescription {
public:
TestDescription_suite_uriTestSuite_test_is_unc() : CxxTest::RealTestDescription( Tests_uriTestSuite, suiteDescription_uriTestSuite, 69, "test_is_unc" ) {}
void runTest() { suite_uriTestSuite.test_is_unc(); }
} testDescription_suite_uriTestSuite_test_is_unc;
static class TestDescription_suite_uriTestSuite_test_local_path : public CxxTest::RealTestDescription {
public:
TestDescription_suite_uriTestSuite_test_local_path() : CxxTest::RealTestDescription( Tests_uriTestSuite, suiteDescription_uriTestSuite, 74, "test_local_path" ) {}
void runTest() { suite_uriTestSuite.test_local_path(); }
} testDescription_suite_uriTestSuite_test_local_path;
static class TestDescription_suite_uriTestSuite_test_original_string : public CxxTest::RealTestDescription {
public:
TestDescription_suite_uriTestSuite_test_original_string() : CxxTest::RealTestDescription( Tests_uriTestSuite, suiteDescription_uriTestSuite, 79, "test_original_string" ) {}
void runTest() { suite_uriTestSuite.test_original_string(); }
} testDescription_suite_uriTestSuite_test_original_string;
static class TestDescription_suite_uriTestSuite_test_path_and_query : public CxxTest::RealTestDescription {
public:
TestDescription_suite_uriTestSuite_test_path_and_query() : CxxTest::RealTestDescription( Tests_uriTestSuite, suiteDescription_uriTestSuite, 84, "test_path_and_query" ) {}
void runTest() { suite_uriTestSuite.test_path_and_query(); }
} testDescription_suite_uriTestSuite_test_path_and_query;
static class TestDescription_suite_uriTestSuite_test_port : public CxxTest::RealTestDescription {
public:
TestDescription_suite_uriTestSuite_test_port() : CxxTest::RealTestDescription( Tests_uriTestSuite, suiteDescription_uriTestSuite, 89, "test_port" ) {}
void runTest() { suite_uriTestSuite.test_port(); }
} testDescription_suite_uriTestSuite_test_port;
static class TestDescription_suite_uriTestSuite_test_query : public CxxTest::RealTestDescription {
public:
TestDescription_suite_uriTestSuite_test_query() : CxxTest::RealTestDescription( Tests_uriTestSuite, suiteDescription_uriTestSuite, 94, "test_query" ) {}
void runTest() { suite_uriTestSuite.test_query(); }
} testDescription_suite_uriTestSuite_test_query;
static class TestDescription_suite_uriTestSuite_test_scheme : public CxxTest::RealTestDescription {
public:
TestDescription_suite_uriTestSuite_test_scheme() : CxxTest::RealTestDescription( Tests_uriTestSuite, suiteDescription_uriTestSuite, 99, "test_scheme" ) {}
void runTest() { suite_uriTestSuite.test_scheme(); }
} testDescription_suite_uriTestSuite_test_scheme;
static class TestDescription_suite_uriTestSuite_test_user_escaped : public CxxTest::RealTestDescription {
public:
TestDescription_suite_uriTestSuite_test_user_escaped() : CxxTest::RealTestDescription( Tests_uriTestSuite, suiteDescription_uriTestSuite, 104, "test_user_escaped" ) {}
void runTest() { suite_uriTestSuite.test_user_escaped(); }
} testDescription_suite_uriTestSuite_test_user_escaped;
static class TestDescription_suite_uriTestSuite_test_user_info : public CxxTest::RealTestDescription {
public:
TestDescription_suite_uriTestSuite_test_user_info() : CxxTest::RealTestDescription( Tests_uriTestSuite, suiteDescription_uriTestSuite, 109, "test_user_info" ) {}
void runTest() { suite_uriTestSuite.test_user_info(); }
} testDescription_suite_uriTestSuite_test_user_info;
#include <cxxtest/Root.cpp>
const char* CxxTest::RealWorldDescription::_worldName = "cxxtest";

10
source/writer/writer.cpp Normal file
View File

@ -0,0 +1,10 @@
#include "writer.h"
namespace xlnt {
void writer::save_workbook(const workbook &/*workbook*/, const std::string &/*filename*/)
{
}
} // namespace xlnt