solocraft + dynamicxp

This commit is contained in:
mikx
2023-11-05 15:26:19 -05:00
commit 146bd781e2
3402 changed files with 2098316 additions and 0 deletions

15
src/tools/CMakeLists.txt Normal file
View File

@@ -0,0 +1,15 @@
# Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
#
# This file is free software; as a special exception the author gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
add_subdirectory(map_extractor)
add_subdirectory(vmap4_assembler)
add_subdirectory(vmap4_extractor)
add_subdirectory(mmaps_generator)
add_subdirectory(web_api)

View File

@@ -0,0 +1,44 @@
# Copyright (C) 2005-2009 MaNGOS project <http://getmangos.com/>
# Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
#
# This file is free software; as a special exception the author gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
file(GLOB_RECURSE sources *.cpp *.h)
include_directories (
${CMAKE_SOURCE_DIR}/src/server/shared
${CMAKE_SOURCE_DIR}/dep/CascLib/src
${CMAKE_SOURCE_DIR}/dep/cppformat
${CMAKE_SOURCE_DIR}/dep/g3dlite/include
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/loadlib
)
include_directories(${include_Dirs})
add_executable(mapextractor
${sources}
)
target_link_libraries(mapextractor
casc
common
g3dlib
${BZIP2_LIBRARIES}
${ZLIB_LIBRARIES}
${Boost_LIBRARIES}
)
add_dependencies(mapextractor casc)
if( UNIX )
install(TARGETS mapextractor DESTINATION bin)
elseif( WIN32 )
install(TARGETS mapextractor DESTINATION "${CMAKE_INSTALL_PREFIX}")
endif()

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,240 @@
/*
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ADT_H
#define ADT_H
#include "loadlib.h"
#define TILESIZE (533.33333f)
#define CHUNKSIZE ((TILESIZE) / 16.0f)
#define UNITSIZE (CHUNKSIZE / 8.0f)
enum LiquidType
{
LIQUID_TYPE_WATER = 0,
LIQUID_TYPE_OCEAN = 1,
LIQUID_TYPE_MAGMA = 2,
LIQUID_TYPE_SLIME = 3
};
//**************************************************************************************
// ADT file class
//**************************************************************************************
#define ADT_CELLS_PER_GRID 16
#define ADT_CELL_SIZE 8
#define ADT_GRID_SIZE (ADT_CELLS_PER_GRID*ADT_CELL_SIZE)
#pragma pack(push, 1)
//
// Adt file height map chunk
//
struct adt_MCVT
{
union{
uint32 fcc;
char fcc_txt[4];
};
uint32 size;
float height_map[(ADT_CELL_SIZE+1)*(ADT_CELL_SIZE+1)+ADT_CELL_SIZE*ADT_CELL_SIZE];
};
//
// Adt file liquid map chunk (old)
//
struct adt_MCLQ
{
union{
uint32 fcc;
char fcc_txt[4];
};
uint32 size;
float height1;
float height2;
struct liquid_data{
uint32 light;
float height;
} liquid[ADT_CELL_SIZE+1][ADT_CELL_SIZE+1];
// 1<<0 - ochen
// 1<<1 - lava/slime
// 1<<2 - water
// 1<<6 - all water
// 1<<7 - dark water
// == 0x0F - not show liquid
uint8 flags[ADT_CELL_SIZE][ADT_CELL_SIZE];
uint8 data[84];
};
//
// Adt file cell chunk
//
struct adt_MCNK
{
union{
uint32 fcc;
char fcc_txt[4];
};
uint32 size;
uint32 flags;
uint32 ix;
uint32 iy;
uint32 nLayers;
uint32 nDoodadRefs;
union
{
struct
{
uint32 offsMCVT; // height map
uint32 offsMCNR; // Normal vectors for each vertex
} offsets;
uint8 HighResHoles[8];
} union_5_3_0;
uint32 offsMCLY; // Texture layer definitions
uint32 offsMCRF; // A list of indices into the parent file's MDDF chunk
uint32 offsMCAL; // Alpha maps for additional texture layers
uint32 sizeMCAL;
uint32 offsMCSH; // Shadow map for static shadows on the terrain
uint32 sizeMCSH;
uint32 areaid;
uint32 nMapObjRefs;
uint32 holes;
uint16 s[2];
uint32 data1;
uint32 data2;
uint32 data3;
uint32 predTex;
uint32 nEffectDoodad;
uint32 offsMCSE;
uint32 nSndEmitters;
uint32 offsMCLQ; // Liqid level (old)
uint32 sizeMCLQ; //
float zpos;
float xpos;
float ypos;
uint32 offsMCCV; // offsColorValues in WotLK
uint32 props;
uint32 effectId;
};
#define ADT_LIQUID_HEADER_FULL_LIGHT 0x01
#define ADT_LIQUID_HEADER_NO_HIGHT 0x02
struct adt_liquid_header
{
uint16 liquidType; // Index from LiquidType.dbc
uint16 formatFlags;
float heightLevel1;
float heightLevel2;
uint8 xOffset;
uint8 yOffset;
uint8 width;
uint8 height;
uint32 offsData2a;
uint32 offsData2b;
};
//
// Adt file liquid data chunk (new)
//
struct adt_MH2O
{
union{
uint32 fcc;
char fcc_txt[4];
};
uint32 size;
struct adt_LIQUID{
uint32 offsData1;
uint32 used;
uint32 offsData2;
} liquid[ADT_CELLS_PER_GRID][ADT_CELLS_PER_GRID];
adt_liquid_header *getLiquidData(int x, int y)
{
if (liquid[x][y].used && liquid[x][y].offsData1)
return (adt_liquid_header *)((uint8*)this + 8 + liquid[x][y].offsData1);
return 0;
}
float *getLiquidHeightMap(adt_liquid_header *h)
{
if (h->formatFlags & ADT_LIQUID_HEADER_NO_HIGHT)
return 0;
if (h->offsData2b)
return (float *)((uint8*)this + 8 + h->offsData2b);
return 0;
}
uint8 *getLiquidLightMap(adt_liquid_header *h)
{
if (h->formatFlags&ADT_LIQUID_HEADER_FULL_LIGHT)
return 0;
if (h->offsData2b)
{
if (h->formatFlags & ADT_LIQUID_HEADER_NO_HIGHT)
return (uint8 *)((uint8*)this + 8 + h->offsData2b);
return (uint8 *)((uint8*)this + 8 + h->offsData2b + (h->width+1)*(h->height+1)*4);
}
return 0;
}
uint32 *getLiquidFullLightMap(adt_liquid_header *h)
{
if (!(h->formatFlags&ADT_LIQUID_HEADER_FULL_LIGHT))
return 0;
if (h->offsData2b)
{
if (h->formatFlags & ADT_LIQUID_HEADER_NO_HIGHT)
return (uint32 *)((uint8*)this + 8 + h->offsData2b);
return (uint32 *)((uint8*)this + 8 + h->offsData2b + (h->width+1)*(h->height+1)*4);
}
return 0;
}
uint64 getLiquidShowMap(adt_liquid_header *h)
{
if (h->offsData2a)
return *((uint64 *)((uint8*)this + 8 + h->offsData2a));
else
return 0xFFFFFFFFFFFFFFFFuLL;
}
};
struct adt_MFBO
{
union
{
uint32 fcc;
char fcc_txt[4];
};
uint32 size;
struct plane
{
int16 coords[9];
};
plane max;
plane min;
};
#pragma pack(pop)
#endif

View File

@@ -0,0 +1,209 @@
/*
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define _CRT_SECURE_NO_DEPRECATE
#include "dbcfile.h"
DBCFile::DBCFile(char const* file, char const* fmt)
{
_file = file;
_fmt = fmt;
recordTable = nullptr;
stringTable = nullptr;
fieldsOffset = nullptr;
header.RecordSize = 0;
header.RecordCount = 0;
header.FieldCount = 0;
header.BlockValue = 0;
header.Signature = 0;
header.Hash = 0;
header.Build = 0;
header.TimeStamp = 0;
header.Min = 0;
header.Max = 0;
header.Locale = 0;
header.ReferenceDataSize = 0;
header.MetaFlags = 0;
}
bool DBCFile::open()
{
if (recordTable)
{
delete[] recordTable;
recordTable = nullptr;
}
FILE* f = fopen(_file, "rb");
if (!f)
return false;
if (fread(&header.Signature, sizeof(uint32), 1, f) != 1)
{
fclose(f);
return false;
}
if (fread(&header.RecordCount, sizeof(uint32), 1, f) != 1)
{
fclose(f);
return false;
}
if (fread(&header.FieldCount, sizeof(uint32), 1, f) != 1)
{
fclose(f);
return false;
}
if (fread(&header.RecordSize, sizeof(uint32), 1, f) != 1)
{
fclose(f);
return false;
}
if (fread(&header.BlockValue, sizeof(uint32), 1, f) != 1)
{
fclose(f);
return false;
}
fread(&header.Hash, sizeof(uint32), 1, f);
fread(&header.Build, sizeof(uint32), 1, f);
fread(&header.TimeStamp, sizeof(uint32), 1, f);
fread(&header.Min, sizeof(uint32), 1, f);
fread(&header.Max, sizeof(uint32), 1, f);
fread(&header.Locale, sizeof(uint32), 1, f);
fread(&header.ReferenceDataSize, sizeof(uint32), 1, f);
//fread(&header.MetaFlags, sizeof(uint32), 1, f);
recordTable = new unsigned char[header.RecordSize * header.RecordCount + header.BlockValue];
stringTable = recordTable + header.RecordSize * header.RecordCount;
if (fread(recordTable, header.RecordSize * header.RecordCount + header.BlockValue, 1, f) != 1)
{
fclose(f);
return false;
}
fieldsOffset = new uint32[header.FieldCount];
fieldsOffset[0] = 0;
for (uint32 i = 1; i < header.FieldCount; i++)
{
fieldsOffset[i] = fieldsOffset[i - 1];
switch (_fmt[i - 1])
{
case 'l':
fieldsOffset[i] += sizeof(uint64);
break;
case 'n':
case 'i':
case 'f':
fieldsOffset[i] += sizeof(uint32);
break;
case 't':
fieldsOffset[i] += sizeof(uint16);
break;
case 'b':
fieldsOffset[i] += sizeof(uint8);
break;
case 's':
fieldsOffset[i] += 4/*sizeof(char*)*/; //! WARNING! Size 4
break;
default:
break;
}
}
fclose(f);
return true;
}
DBCFile::~DBCFile()
{
delete[] recordTable;
}
DBCFile::Record DBCFile::getRecord(size_t id)
{
assert(recordTable);
return Record(*this, recordTable + id * header.RecordSize);
}
float DBCFile::Record::getFloat(size_t field) const
{
assert(field < file.header.FieldCount);
return *reinterpret_cast<float*>(offset + file.GetOffset(field));
}
uint32 DBCFile::Record::getUInt(size_t field) const
{
assert(field < file.header.FieldCount);
return *reinterpret_cast<uint32*>(offset + file.GetOffset(field));
}
uint8 DBCFile::Record::getUInt8(size_t field) const
{
assert(field < file.header.FieldCount);
return *reinterpret_cast<uint8*>(offset + file.GetOffset(field));
}
uint16 DBCFile::Record::getUInt16(size_t field) const
{
assert(field < file.header.FieldCount);
return *reinterpret_cast<uint16*>(offset + file.GetOffset(field));
}
uint64 DBCFile::Record::getUInt64(size_t field) const
{
assert(field < file.header.FieldCount);
return *reinterpret_cast<uint64*>(offset + file.GetOffset(field));
}
char const* DBCFile::Record::getString(size_t field) const
{
assert(field < file.header.FieldCount);
return reinterpret_cast<char*>(file.stringTable + getUInt(field));
}
size_t DBCFile::getMaxId()
{
assert(recordTable);
size_t maxId = 0;
for (size_t i = 0; i < getRecordCount(); ++i)
if (maxId < getRecord(i).getUInt(0))
maxId = getRecord(i).getUInt(0);
return maxId;
}
DBCFile::Iterator DBCFile::begin()
{
assert(recordTable);
return Iterator(*this, recordTable);
}
DBCFile::Iterator DBCFile::end()
{
assert(recordTable);
return Iterator(*this, stringTable);
}

View File

@@ -0,0 +1,110 @@
/*
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DBCFILE_H
#define DBCFILE_H
#include <cassert>
#include <string>
#include <list>
#include "Define.h"
class DBCFile
{
public:
DBCFile(char const* file, char const* fmt);
~DBCFile();
bool open();
class Iterator;
class Record
{
public:
float getFloat(size_t field) const;
uint32 getUInt(size_t field) const;
uint8 getUInt8(size_t field) const;
uint16 getUInt16(size_t field) const;
uint64 getUInt64(size_t field) const;
char const* getString(size_t field) const;
private:
Record(DBCFile& file, unsigned char* offset) : file(file), offset(offset) { }
DBCFile& file;
unsigned char* offset;
friend class DBCFile;
friend class DBCFile::Iterator;
Record& operator=(Record const& right);
};
class Iterator
{
public:
Iterator(DBCFile &file, unsigned char* offset) : record(file, offset) { }
Iterator& operator++()
{
record.offset += record.file.header.RecordSize;
return *this;
}
Record const& operator*() const { return record; }
Record const* operator->() const { return &record; }
bool operator==(Iterator const& b) const { return record.offset == b.record.offset; }
bool operator!=(Iterator const& b) const { return record.offset != b.record.offset; }
private:
Record record;
Iterator& operator=(Iterator const& right);
};
Record getRecord(size_t id);
uint32 GetOffset(size_t id) const { return (fieldsOffset != nullptr && id < header.FieldCount) ? fieldsOffset[id] : 0; }
Iterator begin();
Iterator end();
size_t getRecordCount() const { return header.RecordCount; }
size_t getFieldCount() const { return header.FieldCount; }
size_t getMaxId();
private:
uint32* fieldsOffset;
char const* _file;
unsigned char* recordTable;
unsigned char* stringTable;
char const* _fmt;
struct
{
uint32 Signature;
uint32 RecordCount;
uint32 FieldCount;
uint32 RecordSize;
uint32 BlockValue;
uint32 Hash;
uint32 Build;
uint32 TimeStamp;
uint32 Min;
uint32 Max;
uint32 Locale;
uint32 ReferenceDataSize;
uint32 MetaFlags;
} header;
};
#endif

View File

@@ -0,0 +1,201 @@
/*
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define _CRT_SECURE_NO_DEPRECATE
#include "loadlib.h"
#include <cstdio>
u_map_fcc MverMagic = { { 'R','E','V','M' } };
ChunkedFile::ChunkedFile()
{
data = 0;
data_size = 0;
}
ChunkedFile::~ChunkedFile()
{
free();
}
bool ChunkedFile::loadFile(std::string const& fileName, bool log)
{
free();
FILE* f = fopen(fileName.c_str(), "rb");
if (!f)
{
if (log)
printf("No such file %s\n", fileName.c_str());
return false;
}
fseek(f, 0, SEEK_END);
data_size = ftell(f);
rewind(f);
data = new uint8[data_size];
if (fread(data, data_size, 1, f) != 1)
{
fprintf(stderr, "ChunkedFile::loadFile Can't read %s, size=%u ferror %s\n", fileName.c_str(), uint32(data_size), strerror(ferror(f)));
fclose(f);
return false;
}
parseChunks();
if (prepareLoadedData())
{
fclose(f);
return true;
}
printf("ChunkedFile::loadFile Error loading %s\n", fileName.c_str());
fclose(f);
free();
return false;
}
bool ChunkedFile::prepareLoadedData()
{
FileChunk* chunk = GetChunk("MVER");
if (!chunk)
return false;
// Check version
file_MVER* version = chunk->As<file_MVER>();
if (version->fcc != MverMagic.fcc)
return false;
if (version->ver != FILE_FORMAT_VERSION)
return false;
return true;
}
void ChunkedFile::free()
{
for (auto chunk : chunks)
delete chunk.second;
chunks.clear();
delete[] data;
data = 0;
data_size = 0;
}
u_map_fcc InterestingChunks[] =
{
{ { 'R', 'E', 'V', 'M' } },
{ { 'N', 'I', 'A', 'M' } },
{ { 'O', '2', 'H', 'M' } },
{ { 'K', 'N', 'C', 'M' } },
{ { 'T', 'V', 'C', 'M' } },
{ { 'O', 'M', 'W', 'M' } },
{ { 'Q', 'L', 'C', 'M' } },
{ { 'O', 'B', 'F', 'M' } }
};
bool IsInterestingChunk(u_map_fcc const& fcc)
{
for (u_map_fcc const& f : InterestingChunks)
if (f.fcc == fcc.fcc)
return true;
return false;
}
void ChunkedFile::parseChunks()
{
uint8* ptr = GetData();
// Make sure there's enough data to read u_map_fcc struct and the uint32 size after it
while (ptr <= GetData() + GetDataSize() - 8)
{
u_map_fcc header = *(u_map_fcc*)ptr;
if (IsInterestingChunk(header))
{
uint32 size = *(uint32*)(ptr + 4);
if (size <= data_size)
{
std::swap(header.fcc_txt[0], header.fcc_txt[3]);
std::swap(header.fcc_txt[1], header.fcc_txt[2]);
FileChunk* chunk = new FileChunk(ptr, size);
chunk->parseSubChunks();
chunks.insert({ std::string(header.fcc_txt, 4), chunk });
}
// move to next chunk
ptr += size + 8;
}
else
++ptr;
}
}
FileChunk* ChunkedFile::GetChunk(std::string const& name)
{
auto range = chunks.equal_range(name);
if (std::distance(range.first, range.second) == 1)
return range.first->second;
return NULL;
}
FileChunk::~FileChunk()
{
for (auto subchunk : subchunks)
delete subchunk.second;
subchunks.clear();
}
void FileChunk::parseSubChunks()
{
uint8* ptr = data + 8; // skip self
while (ptr < data + size)
{
u_map_fcc header = *(u_map_fcc*)ptr;
if (IsInterestingChunk(header))
{
uint32 subsize = *(uint32*)(ptr + 4);
if (subsize < size)
{
std::swap(header.fcc_txt[0], header.fcc_txt[3]);
std::swap(header.fcc_txt[1], header.fcc_txt[2]);
FileChunk* chunk = new FileChunk(ptr, subsize);
chunk->parseSubChunks();
subchunks.insert({ std::string(header.fcc_txt, 4), chunk });
}
// move to next chunk
ptr += subsize + 8;
}
else
++ptr;
}
}
FileChunk* FileChunk::GetSubChunk(std::string const& name)
{
auto range = subchunks.equal_range(name);
if (std::distance(range.first, range.second) == 1)
return range.first->second;
return NULL;
}

View File

@@ -0,0 +1,599 @@
/*
* Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DBFilesClientList_h__
#define DBFilesClientList_h__
char const* DBFilesClientList[] =
{
"DBFilesClient\\Achievement",
"DBFilesClient\\Achievement_Category",
"DBFilesClient\\AdventureJournal",
"DBFilesClient\\AnimKit",
"DBFilesClient\\AnimKitBoneSet",
"DBFilesClient\\AnimKitBoneSetAlias",
"DBFilesClient\\AnimKitConfig",
"DBFilesClient\\AnimKitConfigBoneSet",
"DBFilesClient\\AnimKitPriority",
"DBFilesClient\\AnimKitSegment",
"DBFilesClient\\AnimReplacement",
"DBFilesClient\\AnimReplacementSet",
"DBFilesClient\\AnimationData",
"DBFilesClient\\AreaGroup",
"DBFilesClient\\AreaGroupMember",
"DBFilesClient\\AreaPOI",
"DBFilesClient\\AreaPOIState",
"DBFilesClient\\AreaTable",
"DBFilesClient\\AreaTrigger",
"DBFilesClient\\AreaTriggerActionSet",
"DBFilesClient\\AreaTriggerBox",
"DBFilesClient\\AreaTriggerCylinder",
"DBFilesClient\\AreaTriggerSphere",
"DBFilesClient\\ArmorLocation",
"DBFilesClient\\AuctionHouse",
"DBFilesClient\\BankBagSlotPrices",
"DBFilesClient\\BannedAddOns",
"DBFilesClient\\BarberShopStyle",
"DBFilesClient\\BattlePetAbility",
"DBFilesClient\\BattlePetAbilityEffect",
"DBFilesClient\\BattlePetAbilityState",
"DBFilesClient\\BattlePetAbilityTurn",
"DBFilesClient\\BattlePetBreedQuality",
"DBFilesClient\\BattlePetBreedState",
"DBFilesClient\\BattlePetEffectProperties",
"DBFilesClient\\BattlePetNPCTeamMember",
"DBFilesClient\\BattlePetSpecies",
"DBFilesClient\\BattlePetSpeciesState",
"DBFilesClient\\BattlePetSpeciesXAbility",
"DBFilesClient\\BattlePetState",
"DBFilesClient\\BattlePetVisual",
"DBFilesClient\\BattlemasterList",
"DBFilesClient\\BroadcastText",
"DBFilesClient\\CameraMode",
"DBFilesClient\\CameraShakes",
"DBFilesClient\\CastableRaidBuffs",
"DBFilesClient\\Cfg_Categories",
"DBFilesClient\\Cfg_Configs",
"DBFilesClient\\Cfg_Regions",
"DBFilesClient\\CharBaseInfo",
"DBFilesClient\\CharBaseSection",
"DBFilesClient\\CharComponentTextureLayouts",
"DBFilesClient\\CharComponentTextureSections",
"DBFilesClient\\CharHairGeosets",
"DBFilesClient\\CharSections",
"DBFilesClient\\CharShipment",
"DBFilesClient\\CharShipmentContainer",
"DBFilesClient\\CharStartOutfit",
"DBFilesClient\\CharTitles",
"DBFilesClient\\CharacterFaceBoneSet",
"DBFilesClient\\CharacterFacialHairStyles",
"DBFilesClient\\CharacterLoadout",
"DBFilesClient\\CharacterLoadoutItem",
"DBFilesClient\\ChatChannels",
"DBFilesClient\\ChatProfanity",
"DBFilesClient\\ChrClasses",
"DBFilesClient\\ChrClassesXPowerTypes",
"DBFilesClient\\ChrRaces",
"DBFilesClient\\ChrSpecialization",
"DBFilesClient\\ChrUpgradeBucket",
"DBFilesClient\\ChrUpgradeBucketSpell",
"DBFilesClient\\ChrUpgradeTier",
"DBFilesClient\\CinematicCamera",
"DBFilesClient\\CinematicSequences",
"DBFilesClient\\CombatCondition",
"DBFilesClient\\Creature",
"DBFilesClient\\CreatureDifficulty",
"DBFilesClient\\CreatureDisplayInfo",
"DBFilesClient\\CreatureDisplayInfoExtra",
"DBFilesClient\\CreatureDisplayInfoTrn",
"DBFilesClient\\CreatureFamily",
"DBFilesClient\\CreatureImmunities",
"DBFilesClient\\CreatureModelData",
"DBFilesClient\\CreatureMovementInfo",
"DBFilesClient\\CreatureSoundData",
"DBFilesClient\\CreatureType",
"DBFilesClient\\Criteria",
"DBFilesClient\\CriteriaTree",
"DBFilesClient\\CriteriaTreeXEffect",
"DBFilesClient\\CurrencyCategory",
"DBFilesClient\\CurrencyTypes",
"DBFilesClient\\Curve",
"DBFilesClient\\CurvePoint",
"DBFilesClient\\DeathThudLookups",
"DBFilesClient\\DeclinedWord",
"DBFilesClient\\DeclinedWordCases",
"DBFilesClient\\DestructibleModelData",
"DBFilesClient\\DeviceBlacklist",
"DBFilesClient\\DeviceDefaultSettings",
"DBFilesClient\\Difficulty",
"DBFilesClient\\DriverBlacklist",
"DBFilesClient\\DungeonEncounter",
"DBFilesClient\\DungeonMap",
"DBFilesClient\\DungeonMapChunk",
"DBFilesClient\\DurabilityCosts",
"DBFilesClient\\DurabilityQuality",
"DBFilesClient\\Emotes",
"DBFilesClient\\EmotesText",
"DBFilesClient\\EmotesTextData",
"DBFilesClient\\EmotesTextSound",
"DBFilesClient\\EnvironmentalDamage",
"DBFilesClient\\Exhaustion",
"DBFilesClient\\Faction",
"DBFilesClient\\FactionGroup",
"DBFilesClient\\FactionTemplate",
"DBFilesClient\\FileData",
"DBFilesClient\\FileDataComplete",
"DBFilesClient\\FootprintTextures",
"DBFilesClient\\FootstepTerrainLookup",
"DBFilesClient\\FriendshipRepReaction",
"DBFilesClient\\FriendshipReputation",
"DBFilesClient\\GMSurveyAnswers",
"DBFilesClient\\GMSurveyCurrentSurvey",
"DBFilesClient\\GMSurveyQuestions",
"DBFilesClient\\GMSurveySurveys",
"DBFilesClient\\GMTicketCategory",
"DBFilesClient\\GameObjectArtKit",
"DBFilesClient\\GameObjectDiffAnimMap",
"DBFilesClient\\GameObjectDisplayInfo",
"DBFilesClient\\GameObjects",
"DBFilesClient\\GameTables",
"DBFilesClient\\GameTips",
"DBFilesClient\\GarrAbility",
"DBFilesClient\\GarrAbilityCategory",
"DBFilesClient\\GarrAbilityEffect",
"DBFilesClient\\GarrBuilding",
"DBFilesClient\\GarrBuildingDoodadSet",
"DBFilesClient\\GarrBuildingPlotInst",
"DBFilesClient\\GarrClassSpec",
"DBFilesClient\\GarrEncounter",
"DBFilesClient\\GarrEncounterXMechanic",
"DBFilesClient\\GarrFollItemSet",
"DBFilesClient\\GarrFollItemSetMember",
"DBFilesClient\\GarrFollower",
"DBFilesClient\\GarrFollowerLevelXP",
"DBFilesClient\\GarrFollowerQuality",
"DBFilesClient\\GarrFollowerType",
"DBFilesClient\\GarrFollowerXAbility",
"DBFilesClient\\GarrMechanic",
"DBFilesClient\\GarrMechanicType",
"DBFilesClient\\GarrMission",
"DBFilesClient\\GarrMissionReward",
"DBFilesClient\\GarrMissionTexture",
"DBFilesClient\\GarrMissionType",
"DBFilesClient\\GarrMissionXEncounter",
"DBFilesClient\\GarrMssnBonusAbility",
"DBFilesClient\\GarrPlot",
"DBFilesClient\\GarrPlotBuilding",
"DBFilesClient\\GarrPlotInstance",
"DBFilesClient\\GarrPlotUICategory",
"DBFilesClient\\GarrSiteLevel",
"DBFilesClient\\GarrSiteLevelPlotInst",
"DBFilesClient\\GarrSpecialization",
"DBFilesClient\\GarrUiAnimClassInfo",
"DBFilesClient\\GarrUiAnimRaceInfo",
"DBFilesClient\\GemProperties",
"DBFilesClient\\GlueScreenEmote",
"DBFilesClient\\GlyphExclusiveCategory",
"DBFilesClient\\GlyphProperties",
"DBFilesClient\\GlyphRequiredSpec",
"DBFilesClient\\GlyphSlot",
"DBFilesClient\\GroundEffectDoodad",
"DBFilesClient\\GroundEffectTexture",
"DBFilesClient\\GroupFinderActivity",
"DBFilesClient\\GroupFinderActivityGrp",
"DBFilesClient\\GroupFinderCategory",
"DBFilesClient\\GuildColorBackground",
"DBFilesClient\\GuildColorBorder",
"DBFilesClient\\GuildColorEmblem",
"DBFilesClient\\GuildPerkSpells",
"DBFilesClient\\Heirloom",
"DBFilesClient\\HelmetAnimScaling",
"DBFilesClient\\HelmetGeosetVisData",
"DBFilesClient\\HighlightColor",
"DBFilesClient\\HolidayDescriptions",
"DBFilesClient\\HolidayNames",
"DBFilesClient\\Holidays",
"DBFilesClient\\ImportPriceArmor",
"DBFilesClient\\ImportPriceQuality",
"DBFilesClient\\ImportPriceShield",
"DBFilesClient\\ImportPriceWeapon",
"DBFilesClient\\Item-sparse",
"DBFilesClient\\Item",
"DBFilesClient\\ItemAppearance",
"DBFilesClient\\ItemArmorQuality",
"DBFilesClient\\ItemArmorShield",
"DBFilesClient\\ItemArmorTotal",
"DBFilesClient\\ItemBagFamily",
"DBFilesClient\\ItemBonus",
"DBFilesClient\\ItemBonusTreeNode",
"DBFilesClient\\ItemClass",
"DBFilesClient\\ItemCurrencyCost",
"DBFilesClient\\ItemDamageAmmo",
"DBFilesClient\\ItemDamageOneHand",
"DBFilesClient\\ItemDamageOneHandCaster",
"DBFilesClient\\ItemDamageRanged",
"DBFilesClient\\ItemDamageThrown",
"DBFilesClient\\ItemDamageTwoHand",
"DBFilesClient\\ItemDamageTwoHandCaster",
"DBFilesClient\\ItemDamageWand",
"DBFilesClient\\ItemDisenchantLoot",
"DBFilesClient\\ItemDisplayInfo",
"DBFilesClient\\ItemEffect",
"DBFilesClient\\ItemExtendedCost",
"DBFilesClient\\ItemGroupSounds",
"DBFilesClient\\ItemLimitCategory",
"DBFilesClient\\ItemModifiedAppearance",
"DBFilesClient\\ItemNameDescription",
"DBFilesClient\\ItemPetFood",
"DBFilesClient\\ItemPriceBase",
"DBFilesClient\\ItemPurchaseGroup",
"DBFilesClient\\ItemRandomProperties",
"DBFilesClient\\ItemRandomSuffix",
"DBFilesClient\\ItemSet",
"DBFilesClient\\ItemSetSpell",
"DBFilesClient\\ItemSpec",
"DBFilesClient\\ItemSpecOverride",
"DBFilesClient\\ItemSubClass",
"DBFilesClient\\ItemSubClassMask",
"DBFilesClient\\ItemToBattlePetSpecies",
"DBFilesClient\\ItemToMountSpell",
"DBFilesClient\\ItemUpgrade",
"DBFilesClient\\ItemUpgradePath",
"DBFilesClient\\ItemVisualEffects",
"DBFilesClient\\ItemVisuals",
"DBFilesClient\\ItemXBonusTree",
"DBFilesClient\\JournalEncounter",
"DBFilesClient\\JournalEncounterCreature",
"DBFilesClient\\JournalEncounterItem",
"DBFilesClient\\JournalEncounterSection",
"DBFilesClient\\JournalEncounterXDifficulty",
"DBFilesClient\\JournalInstance",
"DBFilesClient\\JournalItemXDifficulty",
"DBFilesClient\\JournalSectionXDifficulty",
"DBFilesClient\\JournalTier",
"DBFilesClient\\JournalTierXInstance",
"DBFilesClient\\KeyChain",
"DBFilesClient\\LanguageWords",
"DBFilesClient\\Languages",
"DBFilesClient\\LfgDungeonExpansion",
"DBFilesClient\\LfgDungeonGroup",
"DBFilesClient\\LfgDungeons",
"DBFilesClient\\LfgDungeonsGroupingMap",
"DBFilesClient\\LfgRoleRequirement",
"DBFilesClient\\Light",
"DBFilesClient\\LightData",
"DBFilesClient\\LightParams",
"DBFilesClient\\LightSkybox",
"DBFilesClient\\LiquidMaterial",
"DBFilesClient\\LiquidObject",
"DBFilesClient\\LiquidType",
"DBFilesClient\\LoadingScreenTaxiSplines",
"DBFilesClient\\LoadingScreens",
"DBFilesClient\\Locale",
"DBFilesClient\\Location",
"DBFilesClient\\Lock",
"DBFilesClient\\LockType",
"DBFilesClient\\LookAtController",
"DBFilesClient\\MailTemplate",
"DBFilesClient\\ManifestInterfaceActionIcon",
"DBFilesClient\\ManifestInterfaceData",
"DBFilesClient\\ManifestInterfaceItemIcon",
"DBFilesClient\\ManifestInterfaceTOCData",
"DBFilesClient\\ManifestMP3",
"DBFilesClient\\Map",
"DBFilesClient\\MapChallengeMode",
"DBFilesClient\\MapDifficulty",
"DBFilesClient\\MarketingPromotionsXLocale",
"DBFilesClient\\Material",
"DBFilesClient\\MinorTalent",
"DBFilesClient\\ModelFileData",
"DBFilesClient\\ModelManifest",
"DBFilesClient\\ModelNameToManifest",
"DBFilesClient\\ModifierTree",
"DBFilesClient\\Mount",
"DBFilesClient\\MountCapability",
"DBFilesClient\\MountType",
"DBFilesClient\\MountTypeXCapability",
"DBFilesClient\\Movie",
"DBFilesClient\\MovieFileData",
"DBFilesClient\\MovieOverlays",
"DBFilesClient\\MovieVariation",
"DBFilesClient\\NPCSounds",
"DBFilesClient\\NameGen",
"DBFilesClient\\NamesProfanity",
"DBFilesClient\\NamesReserved",
"DBFilesClient\\NamesReservedLocale",
"DBFilesClient\\ObjectEffect",
"DBFilesClient\\ObjectEffectGroup",
"DBFilesClient\\ObjectEffectModifier",
"DBFilesClient\\ObjectEffectPackage",
"DBFilesClient\\ObjectEffectPackageElem",
"DBFilesClient\\OverrideSpellData",
"DBFilesClient\\PageTextMaterial",
"DBFilesClient\\PaperDollItemFrame",
"DBFilesClient\\ParticleColor",
"DBFilesClient\\Path",
"DBFilesClient\\PathNode",
"DBFilesClient\\PathNodeProperty",
"DBFilesClient\\PathProperty",
"DBFilesClient\\Phase",
"DBFilesClient\\PhaseShiftZoneSounds",
"DBFilesClient\\PhaseXPhaseGroup",
"DBFilesClient\\PlayerCondition",
"DBFilesClient\\PowerDisplay",
"DBFilesClient\\PvpDifficulty",
"DBFilesClient\\PvpItem",
"DBFilesClient\\QuestFactionReward",
"DBFilesClient\\QuestFeedbackEffect",
"DBFilesClient\\QuestInfo",
"DBFilesClient\\QuestLine",
"DBFilesClient\\QuestLineXQuest",
"DBFilesClient\\QuestMoneyReward",
"DBFilesClient\\QuestObjectiveCliTask",
"DBFilesClient\\QuestPOIBlob",
"DBFilesClient\\QuestPOIPoint",
"DBFilesClient\\QuestPOIPointCliTask",
"DBFilesClient\\QuestPackageItem",
"DBFilesClient\\QuestSort",
"DBFilesClient\\QuestV2",
"DBFilesClient\\QuestV2CliTask",
"DBFilesClient\\QuestXP",
"DBFilesClient\\RacialMounts",
"DBFilesClient\\RandPropPoints",
"DBFilesClient\\ResearchBranch",
"DBFilesClient\\ResearchField",
"DBFilesClient\\ResearchProject",
"DBFilesClient\\ResearchSite",
"DBFilesClient\\Resistances",
"DBFilesClient\\RulesetItemUpgrade",
"DBFilesClient\\RulesetRaidLootUpgrade",
"DBFilesClient\\RulesetRaidOverride",
"DBFilesClient\\ScalingStatDistribution",
"DBFilesClient\\Scenario",
"DBFilesClient\\ScenarioEventEntry",
"DBFilesClient\\ScenarioStep",
"DBFilesClient\\SceneScript",
"DBFilesClient\\SceneScriptPackage",
"DBFilesClient\\SceneScriptPackageMember",
"DBFilesClient\\ScreenEffect",
"DBFilesClient\\ScreenLocation",
"DBFilesClient\\ServerMessages",
"DBFilesClient\\SkillLine",
"DBFilesClient\\SkillLineAbility",
"DBFilesClient\\SkillLineAbilitySortedSpell",
"DBFilesClient\\SkillRaceClassInfo",
"DBFilesClient\\SoundAmbience",
"DBFilesClient\\SoundAmbienceFlavor",
"DBFilesClient\\SoundBus",
"DBFilesClient\\SoundBusName",
"DBFilesClient\\SoundEmitterPillPoints",
"DBFilesClient\\SoundEmitters",
"DBFilesClient\\SoundEntries",
"DBFilesClient\\SoundEntriesAdvanced",
"DBFilesClient\\SoundEntriesFallbacks",
"DBFilesClient\\SoundFilter",
"DBFilesClient\\SoundFilterElem",
"DBFilesClient\\SoundOverride",
"DBFilesClient\\SoundProviderPreferences",
"DBFilesClient\\SpamMessages",
"DBFilesClient\\SpecializationSpells",
"DBFilesClient\\Spell",
"DBFilesClient\\SpellActionBarPref",
"DBFilesClient\\SpellActivationOverlay",
"DBFilesClient\\SpellAuraOptions",
"DBFilesClient\\SpellAuraRestrictions",
"DBFilesClient\\SpellAuraRestrictionsDifficulty",
"DBFilesClient\\SpellAuraVisXChrSpec",
"DBFilesClient\\SpellAuraVisibility",
"DBFilesClient\\SpellCastTimes",
"DBFilesClient\\SpellCastingRequirements",
"DBFilesClient\\SpellCategories",
"DBFilesClient\\SpellCategory",
"DBFilesClient\\SpellChainEffects",
"DBFilesClient\\SpellClassOptions",
"DBFilesClient\\SpellCooldowns",
"DBFilesClient\\SpellDescriptionVariables",
"DBFilesClient\\SpellDispelType",
"DBFilesClient\\SpellDuration",
"DBFilesClient\\SpellEffect",
"DBFilesClient\\SpellEffectCameraShakes",
"DBFilesClient\\SpellEffectGroupSize",
"DBFilesClient\\SpellEffectScaling",
"DBFilesClient\\SpellEquippedItems",
"DBFilesClient\\SpellFlyout",
"DBFilesClient\\SpellFlyoutItem",
"DBFilesClient\\SpellFocusObject",
"DBFilesClient\\SpellIcon",
"DBFilesClient\\SpellInterrupts",
"DBFilesClient\\SpellItemEnchantment",
"DBFilesClient\\SpellItemEnchantmentCondition",
"DBFilesClient\\SpellKeyboundOverride",
"DBFilesClient\\SpellLearnSpell",
"DBFilesClient\\SpellLevels",
"DBFilesClient\\SpellMechanic",
"DBFilesClient\\SpellMisc",
"DBFilesClient\\SpellMiscDifficulty",
"DBFilesClient\\SpellMissile",
"DBFilesClient\\SpellMissileMotion",
"DBFilesClient\\SpellPower",
"DBFilesClient\\SpellPowerDifficulty",
"DBFilesClient\\SpellProcsPerMinute",
"DBFilesClient\\SpellProcsPerMinuteMod",
"DBFilesClient\\SpellRadius",
"DBFilesClient\\SpellRange",
"DBFilesClient\\SpellReagents",
"DBFilesClient\\SpellReagentsCurrency",
"DBFilesClient\\SpellRuneCost",
"DBFilesClient\\SpellScaling",
"DBFilesClient\\SpellShapeshift",
"DBFilesClient\\SpellShapeshiftForm",
"DBFilesClient\\SpellSpecialUnitEffect",
"DBFilesClient\\SpellTargetRestrictions",
"DBFilesClient\\SpellTotems",
"DBFilesClient\\SpellVisual",
"DBFilesClient\\SpellVisualColorEffect",
"DBFilesClient\\SpellVisualEffectName",
"DBFilesClient\\SpellVisualKit",
"DBFilesClient\\SpellVisualKitAreaModel",
"DBFilesClient\\SpellVisualKitModelAttach",
"DBFilesClient\\SpellVisualMissile",
"DBFilesClient\\SpellXSpellVisual",
"DBFilesClient\\Startup_Strings",
"DBFilesClient\\Stationery",
"DBFilesClient\\StringLookups",
"DBFilesClient\\SummonProperties",
"DBFilesClient\\Talent",
"DBFilesClient\\TaxiNodes",
"DBFilesClient\\TaxiPath",
"DBFilesClient\\TaxiPathNode",
"DBFilesClient\\TerrainMaterial",
"DBFilesClient\\TerrainType",
"DBFilesClient\\TerrainTypeSounds",
"DBFilesClient\\TextureFileData",
"DBFilesClient\\TotemCategory",
"DBFilesClient\\Toy",
"DBFilesClient\\TradeSkillCategory",
"DBFilesClient\\TransportAnimation",
"DBFilesClient\\TransportPhysics",
"DBFilesClient\\TransportRotation",
"DBFilesClient\\Trophy",
"DBFilesClient\\TrophyInstance",
"DBFilesClient\\TrophyType",
"DBFilesClient\\UiTextureAtlas",
"DBFilesClient\\UiTextureAtlasMember",
"DBFilesClient\\UiTextureKit",
"DBFilesClient\\UnitBlood",
"DBFilesClient\\UnitBloodLevels",
"DBFilesClient\\UnitCondition",
"DBFilesClient\\UnitPowerBar",
"DBFilesClient\\Vehicle",
"DBFilesClient\\VehicleSeat",
"DBFilesClient\\VehicleUIIndSeat",
"DBFilesClient\\VehicleUIIndicator",
"DBFilesClient\\VideoHardware",
"DBFilesClient\\Vignette",
"DBFilesClient\\VocalUISounds",
"DBFilesClient\\WMOAreaTable",
"DBFilesClient\\WbAccessControlList",
"DBFilesClient\\WbCertBlacklist",
"DBFilesClient\\WbCertWhitelist",
"DBFilesClient\\WbPermissions",
"DBFilesClient\\WeaponImpactSounds",
"DBFilesClient\\WeaponSwingSounds2",
"DBFilesClient\\WeaponTrail",
"DBFilesClient\\Weather",
"DBFilesClient\\WindSettings",
"DBFilesClient\\WorldBossLockout",
"DBFilesClient\\WorldChunkSounds",
"DBFilesClient\\WorldEffect",
"DBFilesClient\\WorldElapsedTimer",
"DBFilesClient\\WorldMapArea",
"DBFilesClient\\WorldMapContinent",
"DBFilesClient\\WorldMapOverlay",
"DBFilesClient\\WorldMapTransforms",
"DBFilesClient\\WorldSafeLocs",
"DBFilesClient\\WorldState",
"DBFilesClient\\WorldStateExpression",
"DBFilesClient\\WorldStateUI",
"DBFilesClient\\WorldStateZoneSounds",
"DBFilesClient\\World_PVP_Area",
"DBFilesClient\\ZoneIntroMusicTable",
"DBFilesClient\\ZoneLight",
"DBFilesClient\\ZoneLightPoint",
"DBFilesClient\\ZoneMusic",
"DBFilesClient\\gtArmorMitigationByLvl",
"DBFilesClient\\gtAttackPower",
"DBFilesClient\\gtAttackPowerRanged",
"DBFilesClient\\gtAvoidanceDim",
"DBFilesClient\\gtBarberShopCostBase",
"DBFilesClient\\gtBattlePetTypeDamageMod",
"DBFilesClient\\gtBattlePetXP",
"DBFilesClient\\gtChanceToDodgeBase",
"DBFilesClient\\gtChanceToMeleeCrit",
"DBFilesClient\\gtChanceToMeleeCritBase",
"DBFilesClient\\gtChanceToParryBase",
"DBFilesClient\\gtChanceToSpellCrit",
"DBFilesClient\\gtChanceToSpellCritBase",
"DBFilesClient\\gtCombatRatings",
"DBFilesClient\\gtItemLevelByLevel",
"DBFilesClient\\gtItemSocketCostPerLevel",
"DBFilesClient\\gtNPCExpectedResistPhysExp1",
"DBFilesClient\\gtNPCExpectedResistPhysExp2",
"DBFilesClient\\gtNPCExpectedResistPhysExp3",
"DBFilesClient\\gtNPCExpectedResistPhysExp4",
"DBFilesClient\\gtNPCExpectedResistPhysExp5",
"DBFilesClient\\gtNPCManaCostScaler",
"DBFilesClient\\gtNpcDamageByClass",
"DBFilesClient\\gtNpcDamageByClassExp1",
"DBFilesClient\\gtNpcDamageByClassExp2",
"DBFilesClient\\gtNpcDamageByClassExp3",
"DBFilesClient\\gtNpcDamageByClassExp4",
"DBFilesClient\\gtNpcDamageByClassExp5",
"DBFilesClient\\gtNpcGuildExperience",
"DBFilesClient\\gtNpcTotalHp",
"DBFilesClient\\gtNpcTotalHpExp1",
"DBFilesClient\\gtNpcTotalHpExp2",
"DBFilesClient\\gtNpcTotalHpExp3",
"DBFilesClient\\gtNpcTotalHpExp4",
"DBFilesClient\\gtNpcTotalHpExp5",
"DBFilesClient\\gtNpcTotalMp",
"DBFilesClient\\gtOCTBaseHPByClass",
"DBFilesClient\\gtOCTBaseMPByClass",
"DBFilesClient\\gtOCTChanceToDodge",
"DBFilesClient\\gtOCTChanceToParry",
"DBFilesClient\\gtOCTClassCombatRatingScalar",
"DBFilesClient\\gtOCTClassStats",
"DBFilesClient\\gtOCTHPFromItems",
"DBFilesClient\\gtOCTHpPerStamina",
"DBFilesClient\\gtOCTLevelExperience",
"DBFilesClient\\gtOCTMPFromItems",
"DBFilesClient\\gtOCTMPPerIntellect",
"DBFilesClient\\gtOCTNPCDpsScaler",
"DBFilesClient\\gtOCTNPCExpectedAgility",
"DBFilesClient\\gtOCTNPCExpectedIntellect",
"DBFilesClient\\gtOCTNPCExpectedResistPhysical",
"DBFilesClient\\gtOCTNPCExpectedSpirit",
"DBFilesClient\\gtOCTNPCExpectedStamina",
"DBFilesClient\\gtOCTNPCExpectedStrength",
"DBFilesClient\\gtOCTNPCHPScaler",
"DBFilesClient\\gtOCTRaceStats",
"DBFilesClient\\gtPCBaseAgility",
"DBFilesClient\\gtPCBaseIntellect",
"DBFilesClient\\gtPCBaseSpirit",
"DBFilesClient\\gtPCBaseStamina",
"DBFilesClient\\gtPCBaseStrength",
"DBFilesClient\\gtPCExpectedAgility",
"DBFilesClient\\gtPCExpectedIntellect",
"DBFilesClient\\gtPCExpectedSpirit",
"DBFilesClient\\gtPCExpectedStamina",
"DBFilesClient\\gtPCExpectedStrength",
"DBFilesClient\\gtPVPRanks",
"DBFilesClient\\gtRageGenScaler",
"DBFilesClient\\gtRegenMPPerSpt",
"DBFilesClient\\gtResilienceDR",
"DBFilesClient\\gtResistanceInnateFire",
"DBFilesClient\\gtResistanceInnateFrost",
"DBFilesClient\\gtResistanceInnateHoly",
"DBFilesClient\\gtResistanceInnateNature",
"DBFilesClient\\gtResistanceInnateShadow",
"DBFilesClient\\gtShieldBlockRegular",
"DBFilesClient\\gtSpellScaling",
"DBFilesClient\\gtXPGroupBonus",
nullptr // terminator
};
#endif // DBFilesClientList_h__

View File

@@ -0,0 +1,102 @@
/*
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LOAD_LIB_H
#define LOAD_LIB_H
#include "Define.h"
#ifdef TC_PLATFORM_WINDOWS
#undef TC_PLATFORM_WINDOWS
#endif
#include <map>
#include <cstdint>
#include <string>
#ifndef _WIN32
int GetLastError();
#endif
#define FILE_FORMAT_VERSION 18
#pragma pack(push, 1)
union u_map_fcc
{
char fcc_txt[4];
uint32 fcc;
};
//
// File version chunk
//
struct file_MVER
{
union{
uint32 fcc;
char fcc_txt[4];
};
uint32 size;
uint32 ver;
};
struct file_MWMO
{
u_map_fcc fcc;
uint32 size;
char FileList[1];
};
class FileChunk
{
public:
FileChunk(uint8* data_, uint32 size_) : data(data_), size(size_) { }
~FileChunk();
uint8* data;
uint32 size;
template<class T>
T* As() { return (T*)data; }
void parseSubChunks();
std::multimap<std::string, FileChunk*> subchunks;
FileChunk* GetSubChunk(std::string const& name);
};
class ChunkedFile
{
public:
uint8 *data;
uint32 data_size;
uint8 *GetData() { return data; }
uint32 GetDataSize() { return data_size; }
ChunkedFile();
virtual ~ChunkedFile();
bool prepareLoadedData();
bool loadFile(std::string const& fileName, bool log = true);
void free();
void parseChunks();
std::multimap<std::string, FileChunk*> chunks;
FileChunk* GetChunk(std::string const& name);
};
#pragma pack(pop)
#endif

View File

@@ -0,0 +1,50 @@
/*
* Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef WDT_H
#define WDT_H
#include "loadlib.h"
//**************************************************************************************
// WDT file class and structures
//**************************************************************************************
#define WDT_MAP_SIZE 64
#pragma pack(push, 1)
class wdt_MAIN
{
union
{
uint32 fcc;
char fcc_txt[4];
};
public:
uint32 size;
struct adtData
{
uint32 flag;
uint32 data1;
} adt_list[64][64];
};
#pragma pack(pop)
#endif

View File

@@ -0,0 +1,78 @@
# Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
#
# This file is free software; as a special exception the author gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
file(GLOB_RECURSE mmap_gen_sources *.cpp *.h)
set(mmap_gen_Includes
${CMAKE_BINARY_DIR}
${CMAKE_SOURCE_DIR}/dep/zmqpp
${CMAKE_SOURCE_DIR}/dep/cppformat
${CMAKE_SOURCE_DIR}/dep/libmpq
${CMAKE_SOURCE_DIR}/dep/zlib
${CMAKE_SOURCE_DIR}/dep/bzip2
${CMAKE_SOURCE_DIR}/dep/g3dlite/include
${CMAKE_SOURCE_DIR}/dep/recastnavigation/Recast
${CMAKE_SOURCE_DIR}/dep/recastnavigation/Recast/Include
${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour
${CMAKE_SOURCE_DIR}/dep/recastnavigation/Detour/Include
${CMAKE_SOURCE_DIR}/src/server/shared
${CMAKE_SOURCE_DIR}/src/server/shared/Configuration
${CMAKE_SOURCE_DIR}/src/server/shared/Cryptography
${CMAKE_SOURCE_DIR}/src/server/shared/Cryptography/Authentication
${CMAKE_SOURCE_DIR}/src/server/shared/Database
${CMAKE_SOURCE_DIR}/src/server/shared/Database/Implementation
${CMAKE_SOURCE_DIR}/src/server/shared/DataStores
${CMAKE_SOURCE_DIR}/src/server/shared/Debugging
${CMAKE_SOURCE_DIR}/src/server/shared/Dynamic/LinkedReference
${CMAKE_SOURCE_DIR}/src/server/shared/Dynamic
${CMAKE_SOURCE_DIR}/src/server/shared/Logging
${CMAKE_SOURCE_DIR}/src/server/shared/Networking
${CMAKE_SOURCE_DIR}/src/server/shared/Packets
${CMAKE_SOURCE_DIR}/src/server/shared/Threading
${CMAKE_SOURCE_DIR}/src/server/shared/Utilities
${CMAKE_SOURCE_DIR}/src/server/shared/Threading
${CMAKE_SOURCE_DIR}/src/server/game/Conditions
${CMAKE_SOURCE_DIR}/src/server/collision
${CMAKE_SOURCE_DIR}/src/server/collision/Management
${CMAKE_SOURCE_DIR}/src/server/collision/Maps
${CMAKE_SOURCE_DIR}/src/server/collision/Models
${MYSQL_INCLUDE_DIR}
${OPENSSL_INCLUDE_DIR}
${VALGRIND_INCLUDE_DIR}
${ZMQ_INCLUDE_DIR}
)
if( WIN32 )
set(mmap_gen_Includes
${mmap_gen_Includes}
${CMAKE_SOURCE_DIR}/dep/libmpq/win
)
endif()
include_directories(${mmap_gen_Includes})
add_executable(mmaps_generator ${mmap_gen_sources})
target_link_libraries(mmaps_generator
g3dlib
Recast
Detour
shared
${MYSQL_LIBRARY}
${OPENSSL_LIBRARIES}
${CMAKE_THREAD_LIBS_INIT}
${Boost_LIBRARIES}
)
if( UNIX )
install(TARGETS mmaps_generator DESTINATION bin)
elseif( WIN32 )
install(TARGETS mmaps_generator DESTINATION "${CMAKE_INSTALL_PREFIX}")
endif()

View File

@@ -0,0 +1,69 @@
Generator command line args
--threads [#] Max number of threads used by the generator
Default: 3
--offMeshInput [file.*] Path to file containing off mesh connections data.
Format must be: (see offmesh_example.txt)
"map_id tile_x,tile_y (start_x start_y start_z) (end_x end_y end_z) size //optional comments"
Single mesh connection per line.
--silent [] Make us script friendly. Do not wait for user input
on error or completion.
--bigBaseUnit [true|false] Generate tile/map using bigger basic unit.
Use this option only if you have unexpected gaps.
false: use normal metrics (default)
--maxAngle [#] Max walkable inclination angle
float between 45 and 90 degrees (default 60)
--skipLiquid [true|false] extract liquid data for maps
false: include liquid data (default)
--skipContinents [true|false] continents are maps 0 (Eastern Kingdoms),
1 (Kalimdor), 530 (Outlands), 571 (Northrend)
false: build continents (default)
--skipJunkMaps [true|false] junk maps include some unused
maps, transport maps, and some other
true: skip junk maps (default)
--skipBattlegrounds [true|false] does not include PVP arenas
false: skip battlegrounds (default)
--debugOutput [true|false] create debugging files for use with RecastDemo
if you are only creating mmaps for use with MaNGOS,
you don't want debugging files
false: don't create debugging files (default)
--tile [#,#] Build the specified tile
seperate number with a comma ','
must specify a map number (see below)
if this option is not used, all tiles are built
[#] Build only the map specified by #
this command will build the map regardless of --skip* option settings
if you do not specify a map number, builds all maps that pass the filters specified by --skip* options
examples:
movement_extractor
builds maps using the default settings (see above for defaults)
movement_extractor --skipContinents true
builds the default maps, except continents
movement_extractor 0
builds all tiles of map 0
movement_extractor 0 --tile 34,46
builds only tile 34,46 of map 0 (this is the southern face of blackrock mountain)

View File

@@ -0,0 +1,277 @@
/*
* Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "IntermediateValues.h"
namespace MMAP
{
IntermediateValues::~IntermediateValues()
{
rcFreeCompactHeightfield(compactHeightfield);
rcFreeHeightField(heightfield);
rcFreeContourSet(contours);
rcFreePolyMesh(polyMesh);
rcFreePolyMeshDetail(polyMeshDetail);
}
void IntermediateValues::writeIV(uint32 mapID, uint32 tileX, uint32 tileY)
{
char fileName[255];
char tileString[25];
sprintf(tileString, "[%02u,%02u]: ", tileX, tileY);
printf("%sWriting debug output... \r", tileString);
std::string name("meshes/%04u%02i%02i.");
#define DEBUG_WRITE(fileExtension,data) \
do { \
sprintf(fileName, (name + fileExtension).c_str(), mapID, tileY, tileX); \
FILE* file = fopen(fileName, "wb"); \
if (!file) \
{ \
char message[1024]; \
sprintf(message, "%sFailed to open %s for writing!\n", tileString, fileName); \
perror(message); \
} \
else \
debugWrite(file, data); \
if (file) fclose(file); \
printf("%sWriting debug output... \r", tileString); \
} while (false)
if (heightfield)
DEBUG_WRITE("hf", heightfield);
if (compactHeightfield)
DEBUG_WRITE("chf", compactHeightfield);
if (contours)
DEBUG_WRITE("cs", contours);
if (polyMesh)
DEBUG_WRITE("pmesh", polyMesh);
if (polyMeshDetail)
DEBUG_WRITE("dmesh", polyMeshDetail);
#undef DEBUG_WRITE
}
void IntermediateValues::debugWrite(FILE* file, const rcHeightfield* mesh)
{
if (!file || !mesh)
return;
fwrite(&(mesh->cs), sizeof(float), 1, file);
fwrite(&(mesh->ch), sizeof(float), 1, file);
fwrite(&(mesh->width), sizeof(int), 1, file);
fwrite(&(mesh->height), sizeof(int), 1, file);
fwrite(mesh->bmin, sizeof(float), 3, file);
fwrite(mesh->bmax, sizeof(float), 3, file);
for (int y = 0; y < mesh->height; ++y)
for (int x = 0; x < mesh->width; ++x)
{
rcSpan* span = mesh->spans[x+y*mesh->width];
// first, count the number of spans
int spanCount = 0;
while (span)
{
spanCount++;
span = span->next;
}
// write the span count
fwrite(&spanCount, sizeof(int), 1, file);
// write the spans
span = mesh->spans[x+y*mesh->width];
while (span)
{
fwrite(span, sizeof(rcSpan), 1, file);
span = span->next;
}
}
}
void IntermediateValues::debugWrite(FILE* file, const rcCompactHeightfield* chf)
{
if (!file | !chf)
return;
fwrite(&(chf->width), sizeof(chf->width), 1, file);
fwrite(&(chf->height), sizeof(chf->height), 1, file);
fwrite(&(chf->spanCount), sizeof(chf->spanCount), 1, file);
fwrite(&(chf->walkableHeight), sizeof(chf->walkableHeight), 1, file);
fwrite(&(chf->walkableClimb), sizeof(chf->walkableClimb), 1, file);
fwrite(&(chf->maxDistance), sizeof(chf->maxDistance), 1, file);
fwrite(&(chf->maxRegions), sizeof(chf->maxRegions), 1, file);
fwrite(chf->bmin, sizeof(chf->bmin), 1, file);
fwrite(chf->bmax, sizeof(chf->bmax), 1, file);
fwrite(&(chf->cs), sizeof(chf->cs), 1, file);
fwrite(&(chf->ch), sizeof(chf->ch), 1, file);
int tmp = 0;
if (chf->cells) tmp |= 1;
if (chf->spans) tmp |= 2;
if (chf->dist) tmp |= 4;
if (chf->areas) tmp |= 8;
fwrite(&tmp, sizeof(tmp), 1, file);
if (chf->cells)
fwrite(chf->cells, sizeof(rcCompactCell), chf->width*chf->height, file);
if (chf->spans)
fwrite(chf->spans, sizeof(rcCompactSpan), chf->spanCount, file);
if (chf->dist)
fwrite(chf->dist, sizeof(unsigned short), chf->spanCount, file);
if (chf->areas)
fwrite(chf->areas, sizeof(unsigned char), chf->spanCount, file);
}
void IntermediateValues::debugWrite(FILE* file, const rcContourSet* cs)
{
if (!file || !cs)
return;
fwrite(&(cs->cs), sizeof(float), 1, file);
fwrite(&(cs->ch), sizeof(float), 1, file);
fwrite(cs->bmin, sizeof(float), 3, file);
fwrite(cs->bmax, sizeof(float), 3, file);
fwrite(&(cs->nconts), sizeof(int), 1, file);
for (int i = 0; i < cs->nconts; ++i)
{
fwrite(&cs->conts[i].area, sizeof(unsigned char), 1, file);
fwrite(&cs->conts[i].reg, sizeof(unsigned short), 1, file);
fwrite(&cs->conts[i].nverts, sizeof(int), 1, file);
fwrite(cs->conts[i].verts, sizeof(int), cs->conts[i].nverts*4, file);
fwrite(&cs->conts[i].nrverts, sizeof(int), 1, file);
fwrite(cs->conts[i].rverts, sizeof(int), cs->conts[i].nrverts*4, file);
}
}
void IntermediateValues::debugWrite(FILE* file, const rcPolyMesh* mesh)
{
if (!file || !mesh)
return;
fwrite(&(mesh->cs), sizeof(float), 1, file);
fwrite(&(mesh->ch), sizeof(float), 1, file);
fwrite(&(mesh->nvp), sizeof(int), 1, file);
fwrite(mesh->bmin, sizeof(float), 3, file);
fwrite(mesh->bmax, sizeof(float), 3, file);
fwrite(&(mesh->nverts), sizeof(int), 1, file);
fwrite(mesh->verts, sizeof(unsigned short), mesh->nverts*3, file);
fwrite(&(mesh->npolys), sizeof(int), 1, file);
fwrite(mesh->polys, sizeof(unsigned short), mesh->npolys*mesh->nvp*2, file);
fwrite(mesh->flags, sizeof(unsigned short), mesh->npolys, file);
fwrite(mesh->areas, sizeof(unsigned char), mesh->npolys, file);
fwrite(mesh->regs, sizeof(unsigned short), mesh->npolys, file);
}
void IntermediateValues::debugWrite(FILE* file, const rcPolyMeshDetail* mesh)
{
if (!file || !mesh)
return;
fwrite(&(mesh->nverts), sizeof(int), 1, file);
fwrite(mesh->verts, sizeof(float), mesh->nverts*3, file);
fwrite(&(mesh->ntris), sizeof(int), 1, file);
fwrite(mesh->tris, sizeof(char), mesh->ntris*4, file);
fwrite(&(mesh->nmeshes), sizeof(int), 1, file);
fwrite(mesh->meshes, sizeof(int), mesh->nmeshes*4, file);
}
void IntermediateValues::generateObjFile(uint32 mapID, uint32 tileX, uint32 tileY, MeshData &meshData)
{
char objFileName[255];
sprintf(objFileName, "meshes/map%04u%02u%02u.obj", mapID, tileY, tileX);
FILE* objFile = fopen(objFileName, "wb");
if (!objFile)
{
char message[1024];
sprintf(message, "Failed to open %s for writing!\n", objFileName);
perror(message);
return;
}
G3D::Array<float> allVerts;
G3D::Array<int> allTris;
allTris.append(meshData.liquidTris);
allVerts.append(meshData.liquidVerts);
TerrainBuilder::copyIndices(meshData.solidTris, allTris, allVerts.size() / 3);
allVerts.append(meshData.solidVerts);
float* verts = allVerts.getCArray();
int vertCount = allVerts.size() / 3;
int* tris = allTris.getCArray();
int triCount = allTris.size() / 3;
for (int i = 0; i < allVerts.size() / 3; i++)
fprintf(objFile, "v %f %f %f\n", verts[i*3], verts[i*3 + 1], verts[i*3 + 2]);
for (int i = 0; i < allTris.size() / 3; i++)
fprintf(objFile, "f %i %i %i\n", tris[i*3] + 1, tris[i*3 + 1] + 1, tris[i*3 + 2] + 1);
fclose(objFile);
char tileString[25];
sprintf(tileString, "[%02u,%02u]: ", tileY, tileX);
printf("%sWriting debug output... \r", tileString);
sprintf(objFileName, "meshes/%04u.map", mapID);
objFile = fopen(objFileName, "wb");
if (!objFile)
{
char message[1024];
sprintf(message, "Failed to open %s for writing!\n", objFileName);
perror(message);
return;
}
char b = '\0';
fwrite(&b, sizeof(char), 1, objFile);
fclose(objFile);
sprintf(objFileName, "meshes/%04u%02u%02u.mesh", mapID, tileY, tileX);
objFile = fopen(objFileName, "wb");
if (!objFile)
{
char message[1024];
sprintf(message, "Failed to open %s for writing!\n", objFileName);
perror(message);
return;
}
fwrite(&vertCount, sizeof(int), 1, objFile);
fwrite(verts, sizeof(float), vertCount*3, objFile);
fflush(objFile);
fwrite(&triCount, sizeof(int), 1, objFile);
fwrite(tris, sizeof(int), triCount*3, objFile);
fflush(objFile);
fclose(objFile);
}
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _INTERMEDIATE_VALUES_H
#define _INTERMEDIATE_VALUES_H
#include "PathCommon.h"
#include "TerrainBuilder.h"
#include "Recast.h"
#include "DetourNavMesh.h"
namespace MMAP
{
// this class gathers all debug info holding and output
struct IntermediateValues
{
rcHeightfield* heightfield;
rcCompactHeightfield* compactHeightfield;
rcContourSet* contours;
rcPolyMesh* polyMesh;
rcPolyMeshDetail* polyMeshDetail;
IntermediateValues() : heightfield(NULL), compactHeightfield(NULL),
contours(NULL), polyMesh(NULL), polyMeshDetail(NULL) {}
~IntermediateValues();
void writeIV(uint32 mapID, uint32 tileX, uint32 tileY);
void debugWrite(FILE* file, const rcHeightfield* mesh);
void debugWrite(FILE* file, const rcCompactHeightfield* chf);
void debugWrite(FILE* file, const rcContourSet* cs);
void debugWrite(FILE* file, const rcPolyMesh* mesh);
void debugWrite(FILE* file, const rcPolyMeshDetail* mesh);
void generateObjFile(uint32 mapID, uint32 tileX, uint32 tileY, MeshData &meshData);
};
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,151 @@
/*
* Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _MAP_BUILDER_H
#define _MAP_BUILDER_H
#include <vector>
#include <set>
#include <map>
#include <list>
#include <atomic>
#include <thread>
#include "TerrainBuilder.h"
#include "IntermediateValues.h"
#include "Recast.h"
#include "DetourNavMesh.h"
#include "ProducerConsumerQueue.h"
using namespace VMAP;
namespace MMAP
{
struct MapTiles
{
MapTiles() : m_mapId(uint32(-1)), m_tiles(NULL) {}
MapTiles(uint32 id, std::set<uint32>* tiles) : m_mapId(id), m_tiles(tiles) {}
~MapTiles() {}
uint32 m_mapId;
std::set<uint32>* m_tiles;
bool operator==(uint32 id)
{
return m_mapId == id;
}
};
typedef std::list<MapTiles> TileList;
struct Tile
{
Tile() : chf(NULL), solid(NULL), cset(NULL), pmesh(NULL), dmesh(NULL) {}
~Tile()
{
rcFreeCompactHeightfield(chf);
rcFreeContourSet(cset);
rcFreeHeightField(solid);
rcFreePolyMesh(pmesh);
rcFreePolyMeshDetail(dmesh);
}
rcCompactHeightfield* chf;
rcHeightfield* solid;
rcContourSet* cset;
rcPolyMesh* pmesh;
rcPolyMeshDetail* dmesh;
};
class MapBuilder
{
public:
MapBuilder(float maxWalkableAngle = 70.f,
bool skipLiquid = false,
bool skipContinents = false,
bool skipJunkMaps = true,
bool skipBattlegrounds = false,
bool debugOutput = false,
bool bigBaseUnit = false,
const char* offMeshFilePath = NULL);
~MapBuilder();
// builds all mmap tiles for the specified map id (ignores skip settings)
void buildMap(uint32 mapID);
void buildMeshFromFile(char* name);
// builds an mmap tile for the specified map and its mesh
void buildSingleTile(uint32 mapID, uint32 tileX, uint32 tileY);
// builds list of maps, then builds all of mmap tiles (based on the skip settings)
void buildAllMaps(int threads);
void WorkerThread();
private:
// detect maps and tiles
void discoverTiles();
std::set<uint32>* getTileList(uint32 mapID);
void buildNavMesh(uint32 mapID, dtNavMesh* &navMesh);
void buildTile(uint32 mapID, uint32 tileX, uint32 tileY, dtNavMesh* navMesh);
// move map building
void buildMoveMapTile(uint32 mapID,
uint32 tileX,
uint32 tileY,
MeshData &meshData,
float bmin[3],
float bmax[3],
dtNavMesh* navMesh);
void getTileBounds(uint32 tileX, uint32 tileY,
float* verts, int vertCount,
float* bmin, float* bmax);
void getGridBounds(uint32 mapID, uint32 &minX, uint32 &minY, uint32 &maxX, uint32 &maxY);
bool shouldSkipMap(uint32 mapID);
bool isTransportMap(uint32 mapID);
bool shouldSkipTile(uint32 mapID, uint32 tileX, uint32 tileY);
TerrainBuilder* m_terrainBuilder;
TileList m_tiles;
bool m_debugOutput;
const char* m_offMeshFilePath;
bool m_skipContinents;
bool m_skipJunkMaps;
bool m_skipBattlegrounds;
float m_maxWalkableAngle;
bool m_bigBaseUnit;
// build performance - not really used for now
rcContext* m_rcContext;
std::vector<std::thread> _workerThreads;
ProducerConsumerQueue<uint32> _queue;
std::atomic<bool> _cancelationToken;
};
}
#endif

View File

@@ -0,0 +1,139 @@
/*
* Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _MMAP_COMMON_H
#define _MMAP_COMMON_H
#include <string>
#include <vector>
#include "Common.h"
#ifndef _WIN32
#include <stddef.h>
#include <dirent.h>
#endif
#ifdef __linux__
#include <errno.h>
#endif
enum NavTerrain
{
NAV_EMPTY = 0x00,
NAV_GROUND = 0x01,
NAV_MAGMA = 0x02,
NAV_SLIME = 0x04,
NAV_WATER = 0x08,
NAV_UNUSED1 = 0x10,
NAV_UNUSED2 = 0x20,
NAV_UNUSED3 = 0x40,
NAV_UNUSED4 = 0x80
// we only have 8 bits
};
namespace MMAP
{
inline bool matchWildcardFilter(const char* filter, const char* str)
{
if (!filter || !str)
return false;
// end on null character
while (*filter && *str)
{
if (*filter == '*')
{
if (*++filter == '\0') // wildcard at end of filter means all remaing chars match
return true;
for (;;)
{
if (*filter == *str)
break;
if (*str == '\0')
return false; // reached end of string without matching next filter character
str++;
}
}
else if (*filter != *str)
return false; // mismatch
filter++;
str++;
}
return ((*filter == '\0' || (*filter == '*' && *++filter == '\0')) && *str == '\0');
}
enum ListFilesResult
{
LISTFILE_DIRECTORY_NOT_FOUND = 0,
LISTFILE_OK = 1
};
inline ListFilesResult getDirContents(std::vector<std::string> &fileList, std::string dirpath = ".", std::string filter = "*")
{
#ifdef WIN32
HANDLE hFind;
WIN32_FIND_DATA findFileInfo;
std::string directory;
directory = dirpath + "/" + filter;
hFind = FindFirstFile(directory.c_str(), &findFileInfo);
if (hFind == INVALID_HANDLE_VALUE)
return LISTFILE_DIRECTORY_NOT_FOUND;
do
{
if ((findFileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
fileList.push_back(std::string(findFileInfo.cFileName));
}
while (FindNextFile(hFind, &findFileInfo));
FindClose(hFind);
#else
const char *p = dirpath.c_str();
DIR * dirp = opendir(p);
struct dirent * dp;
while (dirp)
{
errno = 0;
if ((dp = readdir(dirp)) != NULL)
{
if (matchWildcardFilter(filter.c_str(), dp->d_name))
fileList.push_back(std::string(dp->d_name));
}
else
break;
}
if (dirp)
closedir(dirp);
else
return LISTFILE_DIRECTORY_NOT_FOUND;
#endif
return LISTFILE_OK;
}
}
#endif

View File

@@ -0,0 +1,310 @@
/*
* Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "PathCommon.h"
#include "MapBuilder.h"
#include "Timer.h"
#include "Common.h"
#include "Config.h"
#include "DatabaseEnv.h"
#include "Log.h"
#include "ProcessPriority.h"
#include "Util.h"
#include <cstdlib>
#include <iostream>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/program_options.hpp>
#include <openssl/opensslv.h>
#include <openssl/crypto.h>
using namespace MMAP;
LoginDatabaseWorkerPool LoginDatabase;
bool checkDirectories(bool debugOutput)
{
std::vector<std::string> dirFiles;
if (getDirContents(dirFiles, "maps") == LISTFILE_DIRECTORY_NOT_FOUND || dirFiles.empty())
{
printf("'maps' directory is empty or does not exist\n");
return false;
}
dirFiles.clear();
if (getDirContents(dirFiles, "vmaps", "*.vmtree") == LISTFILE_DIRECTORY_NOT_FOUND || dirFiles.empty())
{
printf("'vmaps' directory is empty or does not exist\n");
return false;
}
dirFiles.clear();
if (getDirContents(dirFiles, "mmaps") == LISTFILE_DIRECTORY_NOT_FOUND)
{
printf("'mmaps' directory does not exist\n");
return false;
}
dirFiles.clear();
if (debugOutput)
{
if (getDirContents(dirFiles, "meshes") == LISTFILE_DIRECTORY_NOT_FOUND)
{
printf("'meshes' directory does not exist (no place to put debugOutput files)\n");
return false;
}
}
return true;
}
bool handleArgs(int argc, char** argv,
int &mapnum,
int &tileX,
int &tileY,
float &maxAngle,
bool &skipLiquid,
bool &skipContinents,
bool &skipJunkMaps,
bool &skipBattlegrounds,
bool &debugOutput,
bool &silent,
bool &bigBaseUnit,
char* &offMeshInputPath,
char* &file,
int& threads)
{
char* param = NULL;
for (int i = 1; i < argc; ++i)
{
if (strcmp(argv[i], "--maxAngle") == 0)
{
param = argv[++i];
if (!param)
return false;
float maxangle = atof(param);
if (maxangle <= 90.f && maxangle >= 45.f)
maxAngle = maxangle;
else
printf("invalid option for '--maxAngle', using default\n");
}
else if (strcmp(argv[i], "--threads") == 0)
{
param = argv[++i];
if (!param)
return false;
threads = atoi(param);
printf("Using %i threads to extract mmaps\n", threads);
}
else if (strcmp(argv[i], "--file") == 0)
{
param = argv[++i];
if (!param)
return false;
file = param;
}
else if (strcmp(argv[i], "--tile") == 0)
{
param = argv[++i];
if (!param)
return false;
char* stileX = strtok(param, ",");
char* stileY = strtok(NULL, ",");
int tilex = atoi(stileX);
int tiley = atoi(stileY);
if ((tilex > 0 && tilex < 64) || (tilex == 0 && strcmp(stileX, "0") == 0))
tileX = tilex;
if ((tiley > 0 && tiley < 64) || (tiley == 0 && strcmp(stileY, "0") == 0))
tileY = tiley;
if (tileX < 0 || tileY < 0)
{
printf("invalid tile coords.\n");
return false;
}
}
else if (strcmp(argv[i], "--skipLiquid") == 0)
{
param = argv[++i];
if (!param)
return false;
if (strcmp(param, "true") == 0)
skipLiquid = true;
else if (strcmp(param, "false") == 0)
skipLiquid = false;
else
printf("invalid option for '--skipLiquid', using default\n");
}
else if (strcmp(argv[i], "--skipContinents") == 0)
{
param = argv[++i];
if (!param)
return false;
if (strcmp(param, "true") == 0)
skipContinents = true;
else if (strcmp(param, "false") == 0)
skipContinents = false;
else
printf("invalid option for '--skipContinents', using default\n");
}
else if (strcmp(argv[i], "--skipJunkMaps") == 0)
{
param = argv[++i];
if (!param)
return false;
if (strcmp(param, "true") == 0)
skipJunkMaps = true;
else if (strcmp(param, "false") == 0)
skipJunkMaps = false;
else
printf("invalid option for '--skipJunkMaps', using default\n");
}
else if (strcmp(argv[i], "--skipBattlegrounds") == 0)
{
param = argv[++i];
if (!param)
return false;
if (strcmp(param, "true") == 0)
skipBattlegrounds = true;
else if (strcmp(param, "false") == 0)
skipBattlegrounds = false;
else
printf("invalid option for '--skipBattlegrounds', using default\n");
}
else if (strcmp(argv[i], "--debugOutput") == 0)
{
param = argv[++i];
if (!param)
return false;
if (strcmp(param, "true") == 0)
debugOutput = true;
else if (strcmp(param, "false") == 0)
debugOutput = false;
else
printf("invalid option for '--debugOutput', using default true\n");
}
else if (strcmp(argv[i], "--silent") == 0)
{
silent = true;
}
else if (strcmp(argv[i], "--bigBaseUnit") == 0)
{
param = argv[++i];
if (!param)
return false;
if (strcmp(param, "true") == 0)
bigBaseUnit = true;
else if (strcmp(param, "false") == 0)
bigBaseUnit = false;
else
printf("invalid option for '--bigBaseUnit', using default false\n");
}
else if (strcmp(argv[i], "--offMeshInput") == 0)
{
param = argv[++i];
if (!param)
return false;
offMeshInputPath = param;
}
else
{
int map = atoi(argv[i]);
if (map > 0 || (map == 0 && (strcmp(argv[i], "0") == 0)))
mapnum = map;
else
{
printf("invalid map id\n");
return false;
}
}
}
return true;
}
int finish(const char* message, int returnValue)
{
printf("%s", message);
getchar(); // Wait for user input
return returnValue;
}
int main(int argc, char** argv)
{
int threads = 3, mapnum = -1;
float maxAngle = 70.0f;
int tileX = -1, tileY = -1;
bool skipLiquid = false,
skipContinents = false,
skipJunkMaps = true,
skipBattlegrounds = false,
debugOutput = false,
silent = false,
bigBaseUnit = false;
char* offMeshInputPath = NULL;
char* file = NULL;
bool validParam = handleArgs(argc, argv, mapnum,
tileX, tileY, maxAngle,
skipLiquid, skipContinents, skipJunkMaps, skipBattlegrounds,
debugOutput, silent, bigBaseUnit, offMeshInputPath, file, threads);
if (!validParam)
return silent ? -1 : finish("You have specified invalid parameters", -1);
if (mapnum == -1 && debugOutput)
{
if (silent)
return -2;
printf("You have specifed debug output, but didn't specify a map to generate.\n");
printf("This will generate debug output for ALL maps.\n");
printf("Are you sure you want to continue? (y/n) ");
if (getchar() != 'y')
return 0;
}
if (!checkDirectories(debugOutput))
return silent ? -3 : finish("Press ENTER to close...", -3);
MapBuilder builder(maxAngle, skipLiquid, skipContinents, skipJunkMaps,
skipBattlegrounds, debugOutput, bigBaseUnit, offMeshInputPath);
uint32 start = getMSTime();
if (file)
builder.buildMeshFromFile(file);
else if (tileX > -1 && tileY > -1 && mapnum >= 0)
builder.buildSingleTile(mapnum, tileX, tileY);
else if (mapnum >= 0)
builder.buildMap(uint32(mapnum));
else
builder.buildAllMaps(threads);
if (!silent)
printf("Finished. MMAPS were built in %u ms!\n", GetMSTimeDiffToNow(start));
return 0;
}

View File

@@ -0,0 +1,928 @@
/*
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "TerrainBuilder.h"
#include "MapBuilder.h"
#include "VMapManager2.h"
#include "MapTree.h"
#include "ModelInstance.h"
// ******************************************
// Map file format defines
// ******************************************
struct map_fileheader
{
uint32 mapMagic;
uint32 versionMagic;
uint32 buildMagic;
uint32 areaMapOffset;
uint32 areaMapSize;
uint32 heightMapOffset;
uint32 heightMapSize;
uint32 liquidMapOffset;
uint32 liquidMapSize;
uint32 holesOffset;
uint32 holesSize;
};
#define MAP_HEIGHT_NO_HEIGHT 0x0001
#define MAP_HEIGHT_AS_INT16 0x0002
#define MAP_HEIGHT_AS_INT8 0x0004
struct map_heightHeader
{
uint32 fourcc;
uint32 flags;
float gridHeight;
float gridMaxHeight;
};
#define MAP_LIQUID_NO_TYPE 0x0001
#define MAP_LIQUID_NO_HEIGHT 0x0002
struct map_liquidHeader
{
uint32 fourcc;
uint16 flags;
uint16 liquidType;
uint8 offsetX;
uint8 offsetY;
uint8 width;
uint8 height;
float liquidLevel;
};
#define MAP_LIQUID_TYPE_NO_WATER 0x00
#define MAP_LIQUID_TYPE_WATER 0x01
#define MAP_LIQUID_TYPE_OCEAN 0x02
#define MAP_LIQUID_TYPE_MAGMA 0x04
#define MAP_LIQUID_TYPE_SLIME 0x08
#define MAP_LIQUID_TYPE_DARK_WATER 0x10
#define MAP_LIQUID_TYPE_WMO_WATER 0x20
namespace MMAP
{
char const* MAP_VERSION_MAGIC = "v1.8";
TerrainBuilder::TerrainBuilder(bool skipLiquid) : m_skipLiquid (skipLiquid){ }
TerrainBuilder::~TerrainBuilder() { }
/**************************************************************************/
void TerrainBuilder::getLoopVars(Spot portion, int &loopStart, int &loopEnd, int &loopInc)
{
switch (portion)
{
case ENTIRE:
loopStart = 0;
loopEnd = V8_SIZE_SQ;
loopInc = 1;
break;
case TOP:
loopStart = 0;
loopEnd = V8_SIZE;
loopInc = 1;
break;
case LEFT:
loopStart = 0;
loopEnd = V8_SIZE_SQ - V8_SIZE + 1;
loopInc = V8_SIZE;
break;
case RIGHT:
loopStart = V8_SIZE - 1;
loopEnd = V8_SIZE_SQ;
loopInc = V8_SIZE;
break;
case BOTTOM:
loopStart = V8_SIZE_SQ - V8_SIZE;
loopEnd = V8_SIZE_SQ;
loopInc = 1;
break;
}
}
/**************************************************************************/
void TerrainBuilder::loadMap(uint32 mapID, uint32 tileX, uint32 tileY, MeshData &meshData)
{
if (loadMap(mapID, tileX, tileY, meshData, ENTIRE))
{
loadMap(mapID, tileX+1, tileY, meshData, LEFT);
loadMap(mapID, tileX-1, tileY, meshData, RIGHT);
loadMap(mapID, tileX, tileY+1, meshData, TOP);
loadMap(mapID, tileX, tileY-1, meshData, BOTTOM);
}
}
/**************************************************************************/
bool TerrainBuilder::loadMap(uint32 mapID, uint32 tileX, uint32 tileY, MeshData &meshData, Spot portion)
{
char mapFileName[255];
sprintf(mapFileName, "maps/%04u_%02u_%02u.map", mapID, tileY, tileX);
FILE* mapFile = fopen(mapFileName, "rb");
if (!mapFile)
return false;
map_fileheader fheader;
if (fread(&fheader, sizeof(map_fileheader), 1, mapFile) != 1 ||
fheader.versionMagic != *((uint32 const*)(MAP_VERSION_MAGIC)))
{
fclose(mapFile);
printf("%s is the wrong version, please extract new .map files\n", mapFileName);
return false;
}
map_heightHeader hheader;
fseek(mapFile, fheader.heightMapOffset, SEEK_SET);
bool haveTerrain = false;
bool haveLiquid = false;
if (fread(&hheader, sizeof(map_heightHeader), 1, mapFile) == 1)
{
haveTerrain = !(hheader.flags & MAP_HEIGHT_NO_HEIGHT);
haveLiquid = fheader.liquidMapOffset && !m_skipLiquid;
}
// no data in this map file
if (!haveTerrain && !haveLiquid)
{
fclose(mapFile);
return false;
}
// data used later
uint8 holes[16][16][8];
memset(holes, 0, sizeof(holes));
uint8 liquid_type[16][16];
memset(liquid_type, 0, sizeof(liquid_type));
G3D::Array<int> ltriangles;
G3D::Array<int> ttriangles;
// terrain data
if (haveTerrain)
{
float heightMultiplier;
float V9[V9_SIZE_SQ], V8[V8_SIZE_SQ];
int expected = V9_SIZE_SQ + V8_SIZE_SQ;
if (hheader.flags & MAP_HEIGHT_AS_INT8)
{
uint8 v9[V9_SIZE_SQ];
uint8 v8[V8_SIZE_SQ];
int count = 0;
count += fread(v9, sizeof(uint8), V9_SIZE_SQ, mapFile);
count += fread(v8, sizeof(uint8), V8_SIZE_SQ, mapFile);
if (count != expected)
printf("TerrainBuilder::loadMap: Failed to read some data expected %d, read %d\n", expected, count);
heightMultiplier = (hheader.gridMaxHeight - hheader.gridHeight) / 255;
for (int i = 0; i < V9_SIZE_SQ; ++i)
V9[i] = (float)v9[i]*heightMultiplier + hheader.gridHeight;
for (int i = 0; i < V8_SIZE_SQ; ++i)
V8[i] = (float)v8[i]*heightMultiplier + hheader.gridHeight;
}
else if (hheader.flags & MAP_HEIGHT_AS_INT16)
{
uint16 v9[V9_SIZE_SQ];
uint16 v8[V8_SIZE_SQ];
int count = 0;
count += fread(v9, sizeof(uint16), V9_SIZE_SQ, mapFile);
count += fread(v8, sizeof(uint16), V8_SIZE_SQ, mapFile);
if (count != expected)
printf("TerrainBuilder::loadMap: Failed to read some data expected %d, read %d\n", expected, count);
heightMultiplier = (hheader.gridMaxHeight - hheader.gridHeight) / 65535;
for (int i = 0; i < V9_SIZE_SQ; ++i)
V9[i] = (float)v9[i]*heightMultiplier + hheader.gridHeight;
for (int i = 0; i < V8_SIZE_SQ; ++i)
V8[i] = (float)v8[i]*heightMultiplier + hheader.gridHeight;
}
else
{
int count = 0;
count += fread(V9, sizeof(float), V9_SIZE_SQ, mapFile);
count += fread(V8, sizeof(float), V8_SIZE_SQ, mapFile);
if (count != expected)
printf("TerrainBuilder::loadMap: Failed to read some data expected %d, read %d\n", expected, count);
}
// hole data
if (fheader.holesSize != 0)
{
memset(holes, 0, fheader.holesSize);
fseek(mapFile, fheader.holesOffset, SEEK_SET);
if (fread(holes, fheader.holesSize, 1, mapFile) != 1)
printf("TerrainBuilder::loadMap: Failed to read some data expected 1, read 0\n");
}
int count = meshData.solidVerts.size() / 3;
float xoffset = (float(tileX)-32)*GRID_SIZE;
float yoffset = (float(tileY)-32)*GRID_SIZE;
float coord[3];
for (int i = 0; i < V9_SIZE_SQ; ++i)
{
getHeightCoord(i, GRID_V9, xoffset, yoffset, coord, V9);
meshData.solidVerts.append(coord[0]);
meshData.solidVerts.append(coord[2]);
meshData.solidVerts.append(coord[1]);
}
for (int i = 0; i < V8_SIZE_SQ; ++i)
{
getHeightCoord(i, GRID_V8, xoffset, yoffset, coord, V8);
meshData.solidVerts.append(coord[0]);
meshData.solidVerts.append(coord[2]);
meshData.solidVerts.append(coord[1]);
}
int indices[] = { 0, 0, 0 };
int loopStart = 0, loopEnd = 0, loopInc = 0;
getLoopVars(portion, loopStart, loopEnd, loopInc);
for (int i = loopStart; i < loopEnd; i+=loopInc)
for (int j = TOP; j <= BOTTOM; j+=1)
{
getHeightTriangle(i, Spot(j), indices);
ttriangles.append(indices[2] + count);
ttriangles.append(indices[1] + count);
ttriangles.append(indices[0] + count);
}
}
// liquid data
if (haveLiquid)
{
map_liquidHeader lheader;
fseek(mapFile, fheader.liquidMapOffset, SEEK_SET);
if (fread(&lheader, sizeof(map_liquidHeader), 1, mapFile) != 1)
printf("TerrainBuilder::loadMap: Failed to read some data expected 1, read 0\n");
float* liquid_map = NULL;
if (!(lheader.flags & MAP_LIQUID_NO_TYPE))
if (fread(liquid_type, sizeof(liquid_type), 1, mapFile) != 1)
printf("TerrainBuilder::loadMap: Failed to read some data expected 1, read 0\n");
if (!(lheader.flags & MAP_LIQUID_NO_HEIGHT))
{
uint32 toRead = lheader.width * lheader.height;
liquid_map = new float [toRead];
if (fread(liquid_map, sizeof(float), toRead, mapFile) != toRead)
printf("TerrainBuilder::loadMap: Failed to read some data expected 1, read 0\n");
}
if (liquid_map)
{
int count = meshData.liquidVerts.size() / 3;
float xoffset = (float(tileX)-32)*GRID_SIZE;
float yoffset = (float(tileY)-32)*GRID_SIZE;
float coord[3];
int row, col;
// generate coordinates
if (!(lheader.flags & MAP_LIQUID_NO_HEIGHT))
{
int j = 0;
for (int i = 0; i < V9_SIZE_SQ; ++i)
{
row = i / V9_SIZE;
col = i % V9_SIZE;
if (row < lheader.offsetY || row >= lheader.offsetY + lheader.height ||
col < lheader.offsetX || col >= lheader.offsetX + lheader.width)
{
// dummy vert using invalid height
meshData.liquidVerts.append((xoffset+col*GRID_PART_SIZE)*-1, INVALID_MAP_LIQ_HEIGHT, (yoffset+row*GRID_PART_SIZE)*-1);
continue;
}
getLiquidCoord(i, j, xoffset, yoffset, coord, liquid_map);
meshData.liquidVerts.append(coord[0]);
meshData.liquidVerts.append(coord[2]);
meshData.liquidVerts.append(coord[1]);
j++;
}
}
else
{
for (int i = 0; i < V9_SIZE_SQ; ++i)
{
row = i / V9_SIZE;
col = i % V9_SIZE;
meshData.liquidVerts.append((xoffset+col*GRID_PART_SIZE)*-1, lheader.liquidLevel, (yoffset+row*GRID_PART_SIZE)*-1);
}
}
delete [] liquid_map;
int indices[] = { 0, 0, 0 };
int loopStart = 0, loopEnd = 0, loopInc = 0, triInc = BOTTOM-TOP;
getLoopVars(portion, loopStart, loopEnd, loopInc);
// generate triangles
for (int i = loopStart; i < loopEnd; i+=loopInc)
for (int j = TOP; j <= BOTTOM; j+= triInc)
{
getHeightTriangle(i, Spot(j), indices, true);
ltriangles.append(indices[2] + count);
ltriangles.append(indices[1] + count);
ltriangles.append(indices[0] + count);
}
}
}
fclose(mapFile);
// now that we have gathered the data, we can figure out which parts to keep:
// liquid above ground, ground above liquid
int loopStart = 0, loopEnd = 0, loopInc = 0, tTriCount = 4;
bool useTerrain, useLiquid;
float* lverts = meshData.liquidVerts.getCArray();
int* ltris = ltriangles.getCArray();
float* tverts = meshData.solidVerts.getCArray();
int* ttris = ttriangles.getCArray();
if ((ltriangles.size() + ttriangles.size()) == 0)
return false;
// make a copy of liquid vertices
// used to pad right-bottom frame due to lost vertex data at extraction
float* lverts_copy = NULL;
if (meshData.liquidVerts.size())
{
lverts_copy = new float[meshData.liquidVerts.size()];
memcpy(lverts_copy, lverts, sizeof(float)*meshData.liquidVerts.size());
}
getLoopVars(portion, loopStart, loopEnd, loopInc);
for (int i = loopStart; i < loopEnd; i+=loopInc)
{
for (int j = 0; j < 2; ++j)
{
// default is true, will change to false if needed
useTerrain = true;
useLiquid = true;
uint8 liquidType = MAP_LIQUID_TYPE_NO_WATER;
// FIXME: "warning: the address of liquid_type will always evaluate as true"
// if there is no liquid, don't use liquid
if (!meshData.liquidVerts.size() || !ltriangles.size())
useLiquid = false;
else
{
liquidType = getLiquidType(i, liquid_type);
switch (liquidType)
{
default:
useLiquid = false;
break;
case MAP_LIQUID_TYPE_WATER:
case MAP_LIQUID_TYPE_OCEAN:
// merge different types of water
liquidType = NAV_WATER;
break;
case MAP_LIQUID_TYPE_MAGMA:
liquidType = NAV_MAGMA;
break;
case MAP_LIQUID_TYPE_SLIME:
liquidType = NAV_SLIME;
break;
case MAP_LIQUID_TYPE_DARK_WATER:
// players should not be here, so logically neither should creatures
useTerrain = false;
useLiquid = false;
break;
}
}
// if there is no terrain, don't use terrain
if (!ttriangles.size())
useTerrain = false;
// while extracting ADT data we are losing right-bottom vertices
// this code adds fair approximation of lost data
if (useLiquid)
{
float quadHeight = 0;
uint32 validCount = 0;
for(uint32 idx = 0; idx < 3; idx++)
{
float h = lverts_copy[ltris[idx]*3 + 1];
if (h != INVALID_MAP_LIQ_HEIGHT && h < INVALID_MAP_LIQ_HEIGHT_MAX)
{
quadHeight += h;
validCount++;
}
}
// update vertex height data
if (validCount > 0 && validCount < 3)
{
quadHeight /= validCount;
for(uint32 idx = 0; idx < 3; idx++)
{
float h = lverts[ltris[idx]*3 + 1];
if (h == INVALID_MAP_LIQ_HEIGHT || h > INVALID_MAP_LIQ_HEIGHT_MAX)
lverts[ltris[idx]*3 + 1] = quadHeight;
}
}
// no valid vertexes - don't use this poly at all
if (validCount == 0)
useLiquid = false;
}
// if there is a hole here, don't use the terrain
if (useTerrain && fheader.holesSize != 0)
useTerrain = !isHole(i, holes);
// we use only one terrain kind per quad - pick higher one
if (useTerrain && useLiquid)
{
float minLLevel = INVALID_MAP_LIQ_HEIGHT_MAX;
float maxLLevel = INVALID_MAP_LIQ_HEIGHT;
for(uint32 x = 0; x < 3; x++)
{
float h = lverts[ltris[x]*3 + 1];
if (minLLevel > h)
minLLevel = h;
if (maxLLevel < h)
maxLLevel = h;
}
float maxTLevel = INVALID_MAP_LIQ_HEIGHT;
float minTLevel = INVALID_MAP_LIQ_HEIGHT_MAX;
for(uint32 x = 0; x < 6; x++)
{
float h = tverts[ttris[x]*3 + 1];
if (maxTLevel < h)
maxTLevel = h;
if (minTLevel > h)
minTLevel = h;
}
// terrain under the liquid?
if (minLLevel > maxTLevel)
useTerrain = false;
//liquid under the terrain?
if (minTLevel > maxLLevel)
useLiquid = false;
}
// store the result
if (useLiquid)
{
meshData.liquidType.append(liquidType);
for (int k = 0; k < 3; ++k)
meshData.liquidTris.append(ltris[k]);
}
if (useTerrain)
for (int k = 0; k < 3*tTriCount/2; ++k)
meshData.solidTris.append(ttris[k]);
// advance to next set of triangles
ltris += 3;
ttris += 3*tTriCount/2;
}
}
if (lverts_copy)
delete [] lverts_copy;
return meshData.solidTris.size() || meshData.liquidTris.size();
}
/**************************************************************************/
void TerrainBuilder::getHeightCoord(int index, Grid grid, float xOffset, float yOffset, float* coord, float* v)
{
// wow coords: x, y, height
// coord is mirroed about the horizontal axes
switch (grid)
{
case GRID_V9:
coord[0] = (xOffset + index%(V9_SIZE)*GRID_PART_SIZE) * -1.f;
coord[1] = (yOffset + (int)(index/(V9_SIZE))*GRID_PART_SIZE) * -1.f;
coord[2] = v[index];
break;
case GRID_V8:
coord[0] = (xOffset + index%(V8_SIZE)*GRID_PART_SIZE + GRID_PART_SIZE/2.f) * -1.f;
coord[1] = (yOffset + (int)(index/(V8_SIZE))*GRID_PART_SIZE + GRID_PART_SIZE/2.f) * -1.f;
coord[2] = v[index];
break;
}
}
/**************************************************************************/
void TerrainBuilder::getHeightTriangle(int square, Spot triangle, int* indices, bool liquid/* = false*/)
{
int rowOffset = square/V8_SIZE;
if (!liquid)
switch (triangle)
{
case TOP:
indices[0] = square+rowOffset; // 0-----1 .... 128
indices[1] = square+1+rowOffset; // |\ T /|
indices[2] = (V9_SIZE_SQ)+square; // | \ / |
break; // |L 0 R| .. 127
case LEFT: // | / \ |
indices[0] = square+rowOffset; // |/ B \|
indices[1] = (V9_SIZE_SQ)+square; // 129---130 ... 386
indices[2] = square+V9_SIZE+rowOffset; // |\ /|
break; // | \ / |
case RIGHT: // | 128 | .. 255
indices[0] = square+1+rowOffset; // | / \ |
indices[1] = square+V9_SIZE+1+rowOffset; // |/ \|
indices[2] = (V9_SIZE_SQ)+square; // 258---259 ... 515
break;
case BOTTOM:
indices[0] = (V9_SIZE_SQ)+square;
indices[1] = square+V9_SIZE+1+rowOffset;
indices[2] = square+V9_SIZE+rowOffset;
break;
default: break;
}
else
switch (triangle)
{ // 0-----1 .... 128
case TOP: // |\ |
indices[0] = square+rowOffset; // | \ T |
indices[1] = square+1+rowOffset; // | \ |
indices[2] = square+V9_SIZE+1+rowOffset; // | B \ |
break; // | \|
case BOTTOM: // 129---130 ... 386
indices[0] = square+rowOffset; // |\ |
indices[1] = square+V9_SIZE+1+rowOffset; // | \ |
indices[2] = square+V9_SIZE+rowOffset; // | \ |
break; // | \ |
default: break; // | \|
} // 258---259 ... 515
}
/**************************************************************************/
void TerrainBuilder::getLiquidCoord(int index, int index2, float xOffset, float yOffset, float* coord, float* v)
{
// wow coords: x, y, height
// coord is mirroed about the horizontal axes
coord[0] = (xOffset + index%(V9_SIZE)*GRID_PART_SIZE) * -1.f;
coord[1] = (yOffset + (int)(index/(V9_SIZE))*GRID_PART_SIZE) * -1.f;
coord[2] = v[index2];
}
/**************************************************************************/
bool TerrainBuilder::isHole(int square, uint8 const holes[16][16][8])
{
int row = square / 128;
int col = square % 128;
int cellRow = row / 8; // 8 squares per cell
int cellCol = col / 8;
int holeRow = row % 8;
int holeCol = (square - (row * 128 + cellCol * 8));
return (holes[cellRow][cellCol][holeRow] & (1 << holeCol)) != 0;
}
/**************************************************************************/
uint8 TerrainBuilder::getLiquidType(int square, const uint8 liquid_type[16][16])
{
int row = square / 128;
int col = square % 128;
int cellRow = row / 8; // 8 squares per cell
int cellCol = col / 8;
return liquid_type[cellRow][cellCol];
}
/**************************************************************************/
bool TerrainBuilder::loadVMap(uint32 mapID, uint32 tileX, uint32 tileY, MeshData &meshData)
{
IVMapManager* vmapManager = new VMapManager2();
int result = vmapManager->loadMap("vmaps", mapID, tileX, tileY);
bool retval = false;
do
{
if (result == VMAP_LOAD_RESULT_ERROR)
break;
InstanceTreeMap instanceTrees;
((VMapManager2*)vmapManager)->getInstanceMapTree(instanceTrees);
if (!instanceTrees[mapID])
break;
ModelInstance* models = NULL;
uint32 count = 0;
instanceTrees[mapID]->getModelInstances(models, count);
if (!models)
break;
for (uint32 i = 0; i < count; ++i)
{
ModelInstance instance = models[i];
// model instances exist in tree even though there are instances of that model in this tile
WorldModel* worldModel = instance.getWorldModel();
if (!worldModel)
continue;
// now we have a model to add to the meshdata
retval = true;
std::vector<GroupModel> groupModels;
worldModel->getGroupModels(groupModels);
// all M2s need to have triangle indices reversed
bool isM2 = instance.name.find(".m2") != std::string::npos || instance.name.find(".M2") != std::string::npos;
// transform data
float scale = instance.iScale;
G3D::Matrix3 rotation = G3D::Matrix3::fromEulerAnglesXYZ(G3D::pi()*instance.iRot.z/-180.f, G3D::pi()*instance.iRot.x/-180.f, G3D::pi()*instance.iRot.y/-180.f);
G3D::Vector3 position = instance.iPos;
position.x -= 32*GRID_SIZE;
position.y -= 32*GRID_SIZE;
for (std::vector<GroupModel>::iterator it = groupModels.begin(); it != groupModels.end(); ++it)
{
std::vector<G3D::Vector3> tempVertices;
std::vector<G3D::Vector3> transformedVertices;
std::vector<MeshTriangle> tempTriangles;
WmoLiquid* liquid = NULL;
it->getMeshData(tempVertices, tempTriangles, liquid);
// first handle collision mesh
transform(tempVertices, transformedVertices, scale, rotation, position);
int offset = meshData.solidVerts.size() / 3;
copyVertices(transformedVertices, meshData.solidVerts);
copyIndices(tempTriangles, meshData.solidTris, offset, isM2);
// now handle liquid data
if (liquid)
{
std::vector<G3D::Vector3> liqVerts;
std::vector<int> liqTris;
uint32 tilesX, tilesY, vertsX, vertsY;
G3D::Vector3 corner;
liquid->getPosInfo(tilesX, tilesY, corner);
vertsX = tilesX + 1;
vertsY = tilesY + 1;
uint8* flags = liquid->GetFlagsStorage();
float* data = liquid->GetHeightStorage();
uint8 type = NAV_EMPTY;
// convert liquid type to NavTerrain
switch (liquid->GetType())
{
case 0:
case 1:
type = NAV_WATER;
break;
case 2:
type = NAV_MAGMA;
break;
case 3:
type = NAV_SLIME;
break;
}
// indexing is weird...
// after a lot of trial and error, this is what works:
// vertex = y*vertsX+x
// tile = x*tilesY+y
// flag = y*tilesY+x
G3D::Vector3 vert;
for (uint32 x = 0; x < vertsX; ++x)
for (uint32 y = 0; y < vertsY; ++y)
{
vert = G3D::Vector3(corner.x + x * GRID_PART_SIZE, corner.y + y * GRID_PART_SIZE, data[y*vertsX + x]);
vert = vert * rotation * scale + position;
vert.x *= -1.f;
vert.y *= -1.f;
liqVerts.push_back(vert);
}
int idx1, idx2, idx3, idx4;
uint32 square;
for (uint32 x = 0; x < tilesX; ++x)
for (uint32 y = 0; y < tilesY; ++y)
if ((flags[x+y*tilesX] & 0x0f) != 0x0f)
{
square = x * tilesY + y;
idx1 = square+x;
idx2 = square+1+x;
idx3 = square+tilesY+1+1+x;
idx4 = square+tilesY+1+x;
// top triangle
liqTris.push_back(idx3);
liqTris.push_back(idx2);
liqTris.push_back(idx1);
// bottom triangle
liqTris.push_back(idx4);
liqTris.push_back(idx3);
liqTris.push_back(idx1);
}
uint32 liqOffset = meshData.liquidVerts.size() / 3;
for (uint32 i = 0; i < liqVerts.size(); ++i)
meshData.liquidVerts.append(liqVerts[i].y, liqVerts[i].z, liqVerts[i].x);
for (uint32 i = 0; i < liqTris.size() / 3; ++i)
{
meshData.liquidTris.append(liqTris[i*3+1] + liqOffset, liqTris[i*3+2] + liqOffset, liqTris[i*3] + liqOffset);
meshData.liquidType.append(type);
}
}
}
}
}
while (false);
vmapManager->unloadMap(mapID, tileX, tileY);
delete vmapManager;
return retval;
}
/**************************************************************************/
void TerrainBuilder::transform(std::vector<G3D::Vector3> &source, std::vector<G3D::Vector3> &transformedVertices, float scale, G3D::Matrix3 &rotation, G3D::Vector3 &position)
{
for (std::vector<G3D::Vector3>::iterator it = source.begin(); it != source.end(); ++it)
{
// apply tranform, then mirror along the horizontal axes
G3D::Vector3 v((*it) * rotation * scale + position);
v.x *= -1.f;
v.y *= -1.f;
transformedVertices.push_back(v);
}
}
/**************************************************************************/
void TerrainBuilder::copyVertices(std::vector<G3D::Vector3> &source, G3D::Array<float> &dest)
{
for (std::vector<G3D::Vector3>::iterator it = source.begin(); it != source.end(); ++it)
{
dest.push_back((*it).y);
dest.push_back((*it).z);
dest.push_back((*it).x);
}
}
/**************************************************************************/
void TerrainBuilder::copyIndices(std::vector<MeshTriangle> &source, G3D::Array<int> &dest, int offset, bool flip)
{
if (flip)
{
for (std::vector<MeshTriangle>::iterator it = source.begin(); it != source.end(); ++it)
{
dest.push_back((*it).idx2+offset);
dest.push_back((*it).idx1+offset);
dest.push_back((*it).idx0+offset);
}
}
else
{
for (std::vector<MeshTriangle>::iterator it = source.begin(); it != source.end(); ++it)
{
dest.push_back((*it).idx0+offset);
dest.push_back((*it).idx1+offset);
dest.push_back((*it).idx2+offset);
}
}
}
/**************************************************************************/
void TerrainBuilder::copyIndices(G3D::Array<int> &source, G3D::Array<int> &dest, int offset)
{
int* src = source.getCArray();
for (int32 i = 0; i < source.size(); ++i)
dest.append(src[i] + offset);
}
/**************************************************************************/
void TerrainBuilder::cleanVertices(G3D::Array<float> &verts, G3D::Array<int> &tris)
{
std::map<int, int> vertMap;
int* t = tris.getCArray();
float* v = verts.getCArray();
G3D::Array<float> cleanVerts;
int index, count = 0;
// collect all the vertex indices from triangle
for (int i = 0; i < tris.size(); ++i)
{
if (vertMap.find(t[i]) != vertMap.end())
continue;
std::pair<int, int> val;
val.first = t[i];
index = val.first;
val.second = count;
vertMap.insert(val);
cleanVerts.append(v[index * 3], v[index * 3 + 1], v[index * 3 + 2]);
count++;
}
verts.fastClear();
verts.append(cleanVerts);
cleanVerts.clear();
// update triangles to use new indices
for (int i = 0; i < tris.size(); ++i)
{
std::map<int, int>::iterator it;
if ((it = vertMap.find(t[i])) == vertMap.end())
continue;
t[i] = (*it).second;
}
vertMap.clear();
}
/**************************************************************************/
void TerrainBuilder::loadOffMeshConnections(uint32 mapID, uint32 tileX, uint32 tileY, MeshData &meshData, const char* offMeshFilePath)
{
// no meshfile input given?
if (offMeshFilePath == NULL)
return;
FILE* fp = fopen(offMeshFilePath, "rb");
if (!fp)
{
printf(" loadOffMeshConnections:: input file %s not found!\n", offMeshFilePath);
return;
}
// pretty silly thing, as we parse entire file and load only the tile we need
// but we don't expect this file to be too large
char* buf = new char[512];
while(fgets(buf, 512, fp))
{
float p0[3], p1[3];
uint32 mid, tx, ty;
float size;
if (sscanf(buf, "%u %u,%u (%f %f %f) (%f %f %f) %f", &mid, &tx, &ty,
&p0[0], &p0[1], &p0[2], &p1[0], &p1[1], &p1[2], &size) != 10)
continue;
if (mapID == mid && tileX == tx && tileY == ty)
{
meshData.offMeshConnections.append(p0[1]);
meshData.offMeshConnections.append(p0[2]);
meshData.offMeshConnections.append(p0[0]);
meshData.offMeshConnections.append(p1[1]);
meshData.offMeshConnections.append(p1[2]);
meshData.offMeshConnections.append(p1[0]);
meshData.offMeshConnectionDirs.append(1); // 1 - both direction, 0 - one sided
meshData.offMeshConnectionRads.append(size); // agent size equivalent
// can be used same way as polygon flags
meshData.offMeshConnectionsAreas.append((unsigned char)0xFF);
meshData.offMeshConnectionsFlags.append((unsigned short)0xFF); // all movement masks can make this path
}
}
delete [] buf;
fclose(fp);
}
}

View File

@@ -0,0 +1,132 @@
/*
* Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _MMAP_TERRAIN_BUILDER_H
#define _MMAP_TERRAIN_BUILDER_H
#include "PathCommon.h"
#include "WorldModel.h"
#include "G3D/Array.h"
#include "G3D/Vector3.h"
#include "G3D/Matrix3.h"
namespace MMAP
{
enum Spot
{
TOP = 1,
RIGHT = 2,
LEFT = 3,
BOTTOM = 4,
ENTIRE = 5
};
enum Grid
{
GRID_V8,
GRID_V9
};
static const int V9_SIZE = 129;
static const int V9_SIZE_SQ = V9_SIZE*V9_SIZE;
static const int V8_SIZE = 128;
static const int V8_SIZE_SQ = V8_SIZE*V8_SIZE;
static const float GRID_SIZE = 533.3333f;
static const float GRID_PART_SIZE = GRID_SIZE/V8_SIZE;
// see contrib/extractor/system.cpp, CONF_use_minHeight
static const float INVALID_MAP_LIQ_HEIGHT = -500.f;
static const float INVALID_MAP_LIQ_HEIGHT_MAX = 5000.0f;
// see following files:
// contrib/extractor/system.cpp
// src/game/Map.cpp
struct MeshData
{
G3D::Array<float> solidVerts;
G3D::Array<int> solidTris;
G3D::Array<float> liquidVerts;
G3D::Array<int> liquidTris;
G3D::Array<uint8> liquidType;
// offmesh connection data
G3D::Array<float> offMeshConnections; // [p0y,p0z,p0x,p1y,p1z,p1x] - per connection
G3D::Array<float> offMeshConnectionRads;
G3D::Array<unsigned char> offMeshConnectionDirs;
G3D::Array<unsigned char> offMeshConnectionsAreas;
G3D::Array<unsigned short> offMeshConnectionsFlags;
};
class TerrainBuilder
{
public:
TerrainBuilder(bool skipLiquid);
~TerrainBuilder();
void loadMap(uint32 mapID, uint32 tileX, uint32 tileY, MeshData &meshData);
bool loadVMap(uint32 mapID, uint32 tileX, uint32 tileY, MeshData &meshData);
void loadOffMeshConnections(uint32 mapID, uint32 tileX, uint32 tileY, MeshData &meshData, const char* offMeshFilePath);
bool usesLiquids() { return !m_skipLiquid; }
// vert and triangle methods
static void transform(std::vector<G3D::Vector3> &original, std::vector<G3D::Vector3> &transformed,
float scale, G3D::Matrix3 &rotation, G3D::Vector3 &position);
static void copyVertices(std::vector<G3D::Vector3> &source, G3D::Array<float> &dest);
static void copyIndices(std::vector<VMAP::MeshTriangle> &source, G3D::Array<int> &dest, int offest, bool flip);
static void copyIndices(G3D::Array<int> &src, G3D::Array<int> &dest, int offset);
static void cleanVertices(G3D::Array<float> &verts, G3D::Array<int> &tris);
private:
/// Loads a portion of a map's terrain
bool loadMap(uint32 mapID, uint32 tileX, uint32 tileY, MeshData &meshData, Spot portion);
/// Sets loop variables for selecting only certain parts of a map's terrain
void getLoopVars(Spot portion, int &loopStart, int &loopEnd, int &loopInc);
/// Controls whether liquids are loaded
bool m_skipLiquid;
/// Load the map terrain from file
bool loadHeightMap(uint32 mapID, uint32 tileX, uint32 tileY, G3D::Array<float> &vertices, G3D::Array<int> &triangles, Spot portion);
/// Get the vector coordinate for a specific position
void getHeightCoord(int index, Grid grid, float xOffset, float yOffset, float* coord, float* v);
/// Get the triangle's vector indices for a specific position
void getHeightTriangle(int square, Spot triangle, int* indices, bool liquid = false);
/// Determines if the specific position's triangles should be rendered
bool isHole(int square, uint8 const holes[16][16][8]);
/// Get the liquid vector coordinate for a specific position
void getLiquidCoord(int index, int index2, float xOffset, float yOffset, float* coord, float* v);
/// Get the liquid type for a specific position
uint8 getLiquidType(int square, const uint8 liquid_type[16][16]);
// hide parameterless and copy constructor
TerrainBuilder();
TerrainBuilder(const TerrainBuilder &tb);
};
}
#endif

View File

@@ -0,0 +1,23 @@
/*
* Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <vector>
#include "MapTree.h"
#include "VMapManager2.h"
#include "WorldModel.h"
#include "ModelInstance.h"

View File

@@ -0,0 +1,36 @@
# Copyright (C) 2005-2009 MaNGOS project <http://getmangos.com/>
# Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/>
#
# This file is free software; as a special exception the author gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
include_directories(
${CMAKE_SOURCE_DIR}/dep/g3dlite/include
${CMAKE_SOURCE_DIR}/src/server/shared
${CMAKE_SOURCE_DIR}/src/server/shared/Debugging
${CMAKE_SOURCE_DIR}/src/server/collision
${CMAKE_SOURCE_DIR}/src/server/collision/Maps
${CMAKE_SOURCE_DIR}/src/server/collision/Models
${ACE_INCLUDE_DIR}
${ZLIB_INCLUDE_DIR}
)
add_executable(vmap4assembler VMapAssembler.cpp)
add_dependencies(vmap4assembler casc)
target_link_libraries(vmap4assembler
g3dlib
common
${ZLIB_LIBRARIES}
)
if( UNIX )
install(TARGETS vmap4assembler DESTINATION bin)
elseif( WIN32 )
install(TARGETS vmap4assembler DESTINATION "${CMAKE_INSTALL_PREFIX}")
endif()

View File

@@ -0,0 +1,49 @@
/*
* Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <string>
#include <iostream>
#include "TileAssembler.h"
int main(int argc, char* argv[])
{
if (argc != 3)
{
std::cout << "usage: " << argv[0] << " <raw data dir> <vmap dest dir>" << std::endl;
return 1;
}
std::string src = argv[1];
std::string dest = argv[2];
std::cout << "using " << src << " as source directory and writing output to " << dest << std::endl;
VMAP::TileAssembler* ta = new VMAP::TileAssembler(src, dest);
if (!ta->convertWorld2())
{
std::cout << "exit with errors" << std::endl;
delete ta;
return 1;
}
delete ta;
std::cout << "Ok, all done" << std::endl;
return 0;
}

View File

@@ -0,0 +1,46 @@
# Copyright (C) 2005-2009 MaNGOS project <http://getmangos.com/>
# Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
#
# This file is free software; as a special exception the author gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
file(GLOB_RECURSE sources *.cpp *.h)
# uncomment next line to disable debug mode
add_definitions("-DIOMAP_DEBUG")
# build setup currently only supports libmpq 0.4.x
if( NOT MSVC )
add_definitions("-Wall")
add_definitions("-ggdb")
add_definitions("-O3")
endif()
include_directories(
${CMAKE_SOURCE_DIR}/src/server/shared
${CMAKE_SOURCE_DIR}/dep/CascLib/src
${CMAKE_SOURCE_DIR}/dep/cppformat
)
add_executable(vmap4extractor ${sources})
target_link_libraries(vmap4extractor
casc
common
${BZIP2_LIBRARIES}
${ZLIB_LIBRARIES}
${Boost_LIBRARIES}
)
add_dependencies(vmap4extractor casc)
if( UNIX )
install(TARGETS vmap4extractor DESTINATION bin)
elseif( WIN32 )
install(TARGETS vmap4extractor DESTINATION "${CMAKE_INSTALL_PREFIX}")
endif()

View File

@@ -0,0 +1,204 @@
/*
* Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "vmapexport.h"
#include "adtfile.h"
#include <algorithm>
#include <cstdio>
#ifdef WIN32
#define snprintf _snprintf
#endif
char const* GetPlainName(char const* FileName)
{
const char * szTemp;
if ((szTemp = strrchr(FileName, '\\')) != NULL)
FileName = szTemp + 1;
return FileName;
}
char* GetPlainName(char* FileName)
{
char * szTemp;
if ((szTemp = strrchr(FileName, '\\')) != NULL)
FileName = szTemp + 1;
return FileName;
}
void FixNameCase(char* name, size_t len)
{
char* ptr = name + len - 1;
//extension in lowercase
for (; *ptr != '.'; --ptr)
*ptr |= 0x20;
for (; ptr >= name; --ptr)
{
if (ptr > name && *ptr >= 'A' && *ptr <= 'Z' && isalpha(*(ptr - 1)))
*ptr |= 0x20;
else if ((ptr == name || !isalpha(*(ptr - 1))) && *ptr >= 'a' && *ptr <= 'z')
*ptr &= ~0x20;
}
}
void FixNameSpaces(char* name, size_t len)
{
for (size_t i = 0; i < len - 3; i++)
{
if (name[i] == ' ')
name[i] = '_';
}
}
char* GetExtension(char* FileName)
{
if (char* szTemp = strrchr(FileName, '.'))
return szTemp;
return NULL;
}
ADTFile::ADTFile(char* filename) : ADT(filename), nWMO(0), nMDX(0)
{
Adtfilename.append(filename);
}
bool ADTFile::init(uint32 map_num, uint32 tileX, uint32 tileY)
{
if (ADT.isEof())
return false;
uint32 size;
std::string dirname = std::string(szWorkDirWmo) + "/dir_bin";
FILE *dirfile;
dirfile = fopen(dirname.c_str(), "ab");
if (!dirfile)
{
// printf("Can't open dirfile!'%s'\n", dirname.c_str());
return false;
}
while (!ADT.isEof())
{
char fourcc[5];
ADT.read(&fourcc,4);
ADT.read(&size, 4);
flipcc(fourcc);
fourcc[4] = 0;
size_t nextpos = ADT.getPos() + size;
if (!strcmp(fourcc,"MCIN"))
{
}
else if (!strcmp(fourcc,"MTEX"))
{
}
else if (!strcmp(fourcc,"MMDX"))
{
if (size)
{
char* buf = new char[size];
ADT.read(buf, size);
char* p = buf;
while (p < buf + size)
{
std::string path(p);
char* s = GetPlainName(p);
FixNameCase(s, strlen(s));
FixNameSpaces(s, strlen(s));
ModelInstanceNames.push_back(s);
ExtractSingleModel(path);
p += strlen(p) + 1;
}
delete[] buf;
}
}
else if (!strcmp(fourcc,"MWMO"))
{
if (size)
{
char* buf = new char[size];
ADT.read(buf, size);
char* p = buf;
while (p < buf + size)
{
char* s = GetPlainName(p);
FixNameCase(s, strlen(s));
FixNameSpaces(s, strlen(s));
WmoInstanceNames.push_back(s);
p += strlen(p) + 1;
}
delete[] buf;
}
}
//======================
else if (!strcmp(fourcc,"MDDF"))
{
if (size)
{
nMDX = (int)size / 36;
for (int i=0; i<nMDX; ++i)
{
uint32 id;
ADT.read(&id, 4);
ModelInstance inst(ADT, ModelInstanceNames[id].c_str(), map_num, tileX, tileY, dirfile);
}
ModelInstanceNames.clear();
}
}
else if (!strcmp(fourcc,"MODF"))
{
if (size)
{
nWMO = (int)size / 64;
for (int i=0; i<nWMO; ++i)
{
uint32 id;
ADT.read(&id, 4);
WMOInstance inst(ADT, WmoInstanceNames[id].c_str(), map_num, tileX, tileY, dirfile);
}
WmoInstanceNames.clear();
}
}
//======================
ADT.seek(nextpos);
}
ADT.close();
fclose(dirfile);
return true;
}
ADTFile::~ADTFile()
{
ADT.close();
}

View File

@@ -0,0 +1,143 @@
/*
* Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ADT_H
#define ADT_H
#include "mpqfile.h"
#include "wmo.h"
#include "model.h"
#define TILESIZE (533.33333f)
#define CHUNKSIZE ((TILESIZE) / 16.0f)
#define UNITSIZE (CHUNKSIZE / 8.0f)
class Liquid;
typedef struct
{
float x;
float y;
float z;
}svec;
struct vec
{
double x;
double y;
double z;
};
struct triangle
{
vec v[3];
};
typedef struct
{
float v9[16*8+1][16*8+1];
float v8[16*8][16*8];
}Cell;
typedef struct
{
double v9[9][9];
double v8[8][8];
uint16 area_id;
//Liquid *lq;
float waterlevel[9][9];
uint8 flag;
}chunk;
typedef struct
{
chunk ch[16][16];
}mcell;
struct MapChunkHeader
{
uint32 flags;
uint32 ix;
uint32 iy;
uint32 nLayers;
uint32 nDoodadRefs;
uint32 ofsHeight;
uint32 ofsNormal;
uint32 ofsLayer;
uint32 ofsRefs;
uint32 ofsAlpha;
uint32 sizeAlpha;
uint32 ofsShadow;
uint32 sizeShadow;
uint32 areaid;
uint32 nMapObjRefs;
uint32 holes;
uint16 s1;
uint16 s2;
uint32 d1;
uint32 d2;
uint32 d3;
uint32 predTex;
uint32 nEffectDoodad;
uint32 ofsSndEmitters;
uint32 nSndEmitters;
uint32 ofsLiquid;
uint32 sizeLiquid;
float zpos;
float xpos;
float ypos;
uint32 textureId;
uint32 props;
uint32 effectId;
};
class ADTFile
{
private:
//size_t mcnk_offsets[256], mcnk_sizes[256];
MPQFile ADT;
//mcell Mcell;
std::string Adtfilename;
public:
ADTFile(char* filename);
~ADTFile();
int nWMO;
int nMDX;
std::vector<std::string> WmoInstanceNames;
std::vector<std::string> ModelInstanceNames;
bool init(uint32 map_num, uint32 tileX, uint32 tileY);
//void LoadMapChunks();
//uint32 wmo_count;
/*
const mcell& Getmcell() const
{
return Mcell;
}
*/
};
char const* GetPlainName(char const* FileName);
char* GetPlainName(char* FileName);
char* GetExtension(char* FileName);
void FixNameCase(char* name, size_t len);
void FixNameSpaces(char* name, size_t len);
//void fixMapNamen(char *name, size_t len);
#endif

View File

@@ -0,0 +1,213 @@
/*
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define _CRT_SECURE_NO_DEPRECATE
#include "dbcfile.h"
DBCFile::DBCFile(char const* file, char const* fmt, bool isdbc /*= false*/)
{
_file = file;
_fmt = fmt;
_isDBC = isdbc;
recordTable = nullptr;
stringTable = nullptr;
fieldsOffset = nullptr;
header.RecordSize = 0;
header.RecordCount = 0;
header.FieldCount = 0;
header.BlockValue = 0;
header.Signature = 0;
header.Hash = 0;
header.Build = 0;
header.TimeStamp = 0;
header.Min = 0;
header.Max = 0;
header.Locale = 0;
header.ReferenceDataSize = 0;
header.MetaFlags = 0;
}
bool DBCFile::open()
{
if (recordTable)
{
delete[] recordTable;
recordTable = nullptr;
}
FILE* f = fopen(_file, "rb");
if (!f)
return false;
if (fread(&header.Signature, sizeof(uint32), 1, f) != 1)
{
fclose(f);
return false;
}
if (fread(&header.RecordCount, sizeof(uint32), 1, f) != 1)
{
fclose(f);
return false;
}
if (fread(&header.FieldCount, sizeof(uint32), 1, f) != 1)
{
fclose(f);
return false;
}
if (fread(&header.RecordSize, sizeof(uint32), 1, f) != 1)
{
fclose(f);
return false;
}
if (fread(&header.BlockValue, sizeof(uint32), 1, f) != 1)
{
fclose(f);
return false;
}
if (!_isDBC)
{
fread(&header.Hash, sizeof(uint32), 1, f);
fread(&header.Build, sizeof(uint32), 1, f);
fread(&header.TimeStamp, sizeof(uint32), 1, f);
fread(&header.Min, sizeof(uint32), 1, f);
fread(&header.Max, sizeof(uint32), 1, f);
fread(&header.Locale, sizeof(uint32), 1, f);
fread(&header.ReferenceDataSize, sizeof(uint32), 1, f);
//fread(&header.MetaFlags, sizeof(uint32), 1, f);
}
recordTable = new unsigned char[header.RecordSize * header.RecordCount + header.BlockValue];
stringTable = recordTable + header.RecordSize * header.RecordCount;
if (fread(recordTable, header.RecordSize * header.RecordCount + header.BlockValue, 1, f) != 1)
{
fclose(f);
return false;
}
fieldsOffset = new uint32[header.FieldCount];
fieldsOffset[0] = 0;
for (uint32 i = 1; i < header.FieldCount; i++)
{
fieldsOffset[i] = fieldsOffset[i - 1];
switch (_fmt[i - 1])
{
case 'l':
fieldsOffset[i] += sizeof(uint64);
break;
case 'n':
case 'i':
case 'f':
fieldsOffset[i] += sizeof(uint32);
break;
case 't':
fieldsOffset[i] += sizeof(uint16);
break;
case 'b':
fieldsOffset[i] += sizeof(uint8);
break;
case 's':
fieldsOffset[i] += 4/*sizeof(char*)*/; //! WARNING! Size 4
break;
default:
break;
}
}
fclose(f);
return true;
}
DBCFile::~DBCFile()
{
delete[] recordTable;
}
DBCFile::Record DBCFile::getRecord(size_t id)
{
assert(recordTable);
return Record(*this, recordTable + id * header.RecordSize);
}
float DBCFile::Record::getFloat(size_t field) const
{
assert(field < file.header.FieldCount);
return *reinterpret_cast<float*>(offset + file.GetOffset(field));
}
uint32 DBCFile::Record::getUInt(size_t field) const
{
assert(field < file.header.FieldCount);
return *reinterpret_cast<uint32*>(offset + file.GetOffset(field));
}
uint8 DBCFile::Record::getUInt8(size_t field) const
{
assert(field < file.header.FieldCount);
return *reinterpret_cast<uint8*>(offset + file.GetOffset(field));
}
uint16 DBCFile::Record::getUInt16(size_t field) const
{
assert(field < file.header.FieldCount);
return *reinterpret_cast<uint16*>(offset + file.GetOffset(field));
}
uint64 DBCFile::Record::getUInt64(size_t field) const
{
assert(field < file.header.FieldCount);
return *reinterpret_cast<uint64*>(offset + file.GetOffset(field));
}
char const* DBCFile::Record::getString(size_t field) const
{
assert(field < file.header.FieldCount);
return reinterpret_cast<char*>(file.stringTable + getUInt(field));
}
size_t DBCFile::getMaxId()
{
assert(recordTable);
size_t maxId = 0;
for (size_t i = 0; i < getRecordCount(); ++i)
if (maxId < getRecord(i).getUInt(0))
maxId = getRecord(i).getUInt(0);
return maxId;
}
DBCFile::Iterator DBCFile::begin()
{
assert(recordTable);
return Iterator(*this, recordTable);
}
DBCFile::Iterator DBCFile::end()
{
assert(recordTable);
return Iterator(*this, stringTable);
}

View File

@@ -0,0 +1,111 @@
/*
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DBCFILE_H
#define DBCFILE_H
#include <cassert>
#include <string>
#include <list>
#include "Define.h"
class DBCFile
{
public:
DBCFile(char const* file, char const* fmt, bool isdbc = false);
~DBCFile();
bool open();
class Iterator;
class Record
{
public:
float getFloat(size_t field) const;
uint32 getUInt(size_t field) const;
uint8 getUInt8(size_t field) const;
uint16 getUInt16(size_t field) const;
uint64 getUInt64(size_t field) const;
char const* getString(size_t field) const;
private:
Record(DBCFile& file, unsigned char* offset) : file(file), offset(offset) { }
DBCFile& file;
unsigned char* offset;
friend class DBCFile;
friend class DBCFile::Iterator;
Record& operator=(Record const& right);
};
class Iterator
{
public:
Iterator(DBCFile &file, unsigned char* offset) : record(file, offset) { }
Iterator& operator++()
{
record.offset += record.file.header.RecordSize;
return *this;
}
Record const& operator*() const { return record; }
Record const* operator->() const { return &record; }
bool operator==(Iterator const& b) const { return record.offset == b.record.offset; }
bool operator!=(Iterator const& b) const { return record.offset != b.record.offset; }
private:
Record record;
Iterator& operator=(Iterator const& right);
};
Record getRecord(size_t id);
uint32 GetOffset(size_t id) const { return (fieldsOffset != nullptr && id < header.FieldCount) ? fieldsOffset[id] : 0; }
Iterator begin();
Iterator end();
size_t getRecordCount() const { return header.RecordCount; }
size_t getFieldCount() const { return header.FieldCount; }
size_t getMaxId();
private:
uint32* fieldsOffset;
char const* _file;
unsigned char* recordTable;
unsigned char* stringTable;
char const* _fmt;
bool _isDBC;
struct
{
uint32 Signature;
uint32 RecordCount;
uint32 FieldCount;
uint32 RecordSize;
uint32 BlockValue;
uint32 Hash;
uint32 Build;
uint32 TimeStamp;
uint32 Min;
uint32 Max;
uint32 Locale;
uint32 ReferenceDataSize;
uint32 MetaFlags;
} header;
};
#endif

View File

@@ -0,0 +1,141 @@
/*
* Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "model.h"
#include "dbcfile.h"
#include "adtfile.h"
#include "vmapexport.h"
#include <algorithm>
#include <stdio.h>
bool ExtractSingleModel(std::string& fname)
{
if (fname.substr(fname.length() - 4, 4) == ".mdx")
{
fname.erase(fname.length() - 2, 2);
fname.append("2");
}
std::string originalName = fname;
char* name = GetPlainName((char*)fname.c_str());
FixNameCase(name, strlen(name));
FixNameSpaces(name, strlen(name));
std::string output(szWorkDirWmo);
output += "/";
output += name;
if (FileExists(output.c_str()))
return true;
Model mdl(originalName);
if (!mdl.open())
return false;
return mdl.ConvertToVMAPModel(output.c_str());
}
void ExtractGameobjectModels()
{
printf("Extracting GameObject models...");
DBCFile dbc("DBFilesClient\\GameObjectDisplayInfo.db2", "nifffffffft");
if(!dbc.open())
{
printf("Fatal error: Invalid GameObjectDisplayInfo.db2 file format!\n");
exit(1);
}
DBCFile fileData("DBFilesClient\\FileDataComplete.dbc", "nss", true);
if (!fileData.open())
{
printf("Fatal error: Invalid FileDataComplete.dbc file format!\n");
exit(1);
}
std::string basepath = szWorkDirWmo;
basepath += "/";
std::string path;
std::string modelListPath = basepath + "temp_gameobject_models";
FILE* modelList = fopen(modelListPath.c_str(), "wb");
if (!modelList)
{
printf("Fatal error: Could not open file %s\n", modelListPath.c_str());
return;
}
size_t maxFileId = fileData.getMaxId() + 1;
uint32* fileDataIndex = new uint32[maxFileId];
memset(fileDataIndex, 0, maxFileId * sizeof(uint32));
for (size_t i = 0; i < fileData.getRecordCount(); ++i)
fileDataIndex[fileData.getRecord(i).getUInt(0)] = i;
for (DBCFile::Iterator it = dbc.begin(); it != dbc.end(); ++it)
{
uint32 fileId = it->getUInt(0);
if (!fileId)
continue;
uint32 fileIndex = fileDataIndex[fileId];
if (!fileIndex)
continue;
std::string filepath = fileData.getRecord(fileIndex).getString(1);
std::string filename = fileData.getRecord(fileIndex).getString(2);
path = filepath + filename;
if (path.length() < 4)
continue;
FixNameCase((char*)path.c_str(), path.size());
char* name = GetPlainName((char*)path.c_str());
FixNameSpaces(name, strlen(name));
char* ch_ext = GetExtension(name);
if (!ch_ext)
continue;
strToLower(ch_ext);
bool result = false;
if (!strcmp(ch_ext, ".wmo"))
result = ExtractSingleWmo(path);
else if (!strcmp(ch_ext, ".mdl")) // TODO: extract .mdl files, if needed
continue;
else if (!strcmp(ch_ext, ".mdx") || !strcmp(ch_ext, ".m2"))
result = ExtractSingleModel(path);
if (result)
{
uint32 displayID = it->getUInt(0);
uint32 pathLength = strlen(name);
fwrite(&displayID, sizeof(uint32), 1, modelList);
fwrite(&pathLength, sizeof(uint32), 1, modelList);
fwrite(name, sizeof(char), pathLength, modelList);
}
}
fclose(modelList);
delete[] fileDataIndex;
printf("Done!\n");
}

View File

@@ -0,0 +1,260 @@
/*
* Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "vmapexport.h"
#include "model.h"
#include "wmo.h"
#include "mpqfile.h"
#include <cassert>
#include <algorithm>
#include <cstdio>
Model::Model(std::string &filename) : filename(filename), vertices(0), indices(0)
{
memset(&header, 0, sizeof(header));
}
bool Model::open()
{
MPQFile f(filename.c_str());
if (f.isEof())
{
f.close();
// Do not show this error on console to avoid confusion, the extractor can continue working even if some models fail to load
//printf("Error loading model %s\n", filename.c_str());
return false;
}
_unload();
char fourcc[5];
uint32 size;
while (true)
{
f.read(fourcc, 4);
f.read(&size, 4);
flipcc(fourcc);
fourcc[4] = 0;
size_t nextpos = f.getPos() + size;
if (!size)
break;
char *buf = new char[size];
f.read(buf, size);
if (!strcmp(fourcc, "12DM") || !strcmp(fourcc, "MD21"))
{
memcpy(&header, buf, sizeof(ModelHeader));
//printf("\n ADDDDDDDDD -- %s ---- %u\n", filename.c_str(), header.nBoundingTriangles);
if (header.nBoundingTriangles > 0)
{
vertices = new Vec3D[header.nBoundingVertices];
memcpy(vertices, &(buf[header.ofsBoundingVertices]), header.nBoundingVertices * 12);
for (uint32 i = 0; i<header.nBoundingVertices; i++)
vertices[i] = fixCoordSystem(vertices[i]);
indices = new uint16[header.nBoundingTriangles];
memcpy(indices, &buf[header.ofsBoundingTriangles], header.nBoundingTriangles * 2);
f.close();
return true;
}
f.close();
return false;
}
else if (strcmp(fourcc, "SFID") && strcmp(fourcc, "DIFS"))
printf("\n------>%u -- %s -- %s\n", nextpos, filename.c_str(), fourcc);
f.seek((int) nextpos);
}
//memcpy(&header, f.getBuffer(), sizeof(ModelHeader));
//if (header.nBoundingTriangles > 0)
//{
// f.seek(0);
// f.seekRelative(header.ofsBoundingVertices);
// vertices = new Vec3D[header.nBoundingVertices];
// f.read(vertices,header.nBoundingVertices*12);
// for (uint32 i=0; i<header.nBoundingVertices; i++)
// vertices[i] = fixCoordSystem(vertices[i]);
// f.seek(0);
// f.seekRelative(header.ofsBoundingTriangles);
// indices = new uint16[header.nBoundingTriangles];
// f.read(indices,header.nBoundingTriangles*2);
// f.close();
//}
//else
//{
// //printf("not included %s\n", filename.c_str());
// f.close();
// return false;
//}
f.close();
return false;
}
bool Model::ConvertToVMAPModel(const char * outfilename)
{
int N[12] = {0,0,0,0,0,0,0,0,0,0,0,0};
FILE* output=fopen(outfilename, "wb");
if (!output)
{
printf("Can't create the output file '%s'\n",outfilename);
return false;
}
fwrite(szRawVMAPMagic, 8, 1, output);
uint32 nVertices = header.nBoundingVertices;
fwrite(&nVertices, sizeof(int), 1, output);
uint32 nofgroups = 1;
fwrite(&nofgroups,sizeof(uint32), 1, output);
fwrite(N,4*3,1,output);// rootwmoid, flags, groupid
fwrite(N,sizeof(float),3*2,output);//bbox, only needed for WMO currently
fwrite(N,4,1,output);// liquidflags
fwrite("GRP ",4,1,output);
uint32 branches = 1;
int wsize;
wsize = sizeof(branches) + sizeof(uint32) * branches;
fwrite(&wsize, sizeof(int), 1, output);
fwrite(&branches,sizeof(branches), 1, output);
uint32 nIndexes = header.nBoundingTriangles;
fwrite(&nIndexes,sizeof(uint32), 1, output);
fwrite("INDX",4, 1, output);
wsize = sizeof(uint32) + sizeof(unsigned short) * nIndexes;
fwrite(&wsize, sizeof(int), 1, output);
fwrite(&nIndexes, sizeof(uint32), 1, output);
if (nIndexes > 0)
{
for (uint32 i = 0; i < nIndexes; ++i)
{
if ((i % 3) - 1 == 0 && i + 1 < nIndexes)
{
uint16 tmp = indices[i];
indices[i] = indices[i + 1];
indices[i + 1] = tmp;
}
}
fwrite(indices, sizeof(unsigned short), nIndexes, output);
}
fwrite("VERT", 4, 1, output);
wsize = sizeof(int) + sizeof(float) * 3 * nVertices;
fwrite(&wsize, sizeof(int), 1, output);
fwrite(&nVertices, sizeof(int), 1, output);
if (nVertices >0)
{
for (uint32 vpos = 0; vpos < nVertices; ++vpos)
{
float tmp = vertices[vpos].y;
vertices[vpos].y = -vertices[vpos].z;
vertices[vpos].z = tmp;
}
fwrite(vertices, sizeof(float)*3, nVertices, output);
}
fclose(output);
return true;
}
Vec3D fixCoordSystem(Vec3D v)
{
return Vec3D(v.x, v.z, -v.y);
}
Vec3D fixCoordSystem2(Vec3D v)
{
return Vec3D(v.x, v.z, v.y);
}
ModelInstance::ModelInstance(MPQFile& f, char const* ModelInstName, uint32 mapID, uint32 tileX, uint32 tileY, FILE *pDirfile)
: id(0), scale(0), flags(0)
{
float ff[3];
f.read(&id, 4);
f.read(ff, 12);
pos = fixCoords(Vec3D(ff[0], ff[1], ff[2]));
f.read(ff, 12);
rot = Vec3D(ff[0], ff[1], ff[2]);
f.read(&scale, 2);
f.read(&flags, 2);
// scale factor - divide by 1024. blizzard devs must be on crack, why not just use a float?
sc = scale / 1024.0f;
char tempname[512];
sprintf(tempname, "%s/%s", szWorkDirWmo, ModelInstName);
FILE* input = fopen(tempname, "r+b");
if (!input)
{
// printf("ModelInstance::ModelInstance couldn't open %s\n", tempname);
//system("pause");
return;
}
// printf("ModelInstance::open %s\n", tempname);
fseek(input, 8, SEEK_SET); // get the correct no of vertices
int nVertices;
int count = fread(&nVertices, sizeof (int), 1, input);
fclose(input);
if (count != 1 || nVertices == 0)
return;
uint16 adtId = 0;// not used for models
uint32 flags = MOD_M2;
if (tileX == 65 && tileY == 65)
flags |= MOD_WORLDSPAWN;
//write mapID, tileX, tileY, Flags, ID, Pos, Rot, Scale, name
fwrite(&mapID, sizeof(uint32), 1, pDirfile);
fwrite(&tileX, sizeof(uint32), 1, pDirfile);
fwrite(&tileY, sizeof(uint32), 1, pDirfile);
fwrite(&flags, sizeof(uint32), 1, pDirfile);
fwrite(&adtId, sizeof(uint16), 1, pDirfile);
fwrite(&id, sizeof(uint32), 1, pDirfile);
fwrite(&pos, sizeof(float), 3, pDirfile);
fwrite(&rot, sizeof(float), 3, pDirfile);
fwrite(&sc, sizeof(float), 1, pDirfile);
uint32 nlen=strlen(ModelInstName);
fwrite(&nlen, sizeof(uint32), 1, pDirfile);
fwrite(ModelInstName, sizeof(char), nlen, pDirfile);
/* int realx1 = (int) ((float) pos.x / 533.333333f);
int realy1 = (int) ((float) pos.z / 533.333333f);
int realx2 = (int) ((float) pos.x / 533.333333f);
int realy2 = (int) ((float) pos.z / 533.333333f);
fprintf(pDirfile,"%s/%s %f,%f,%f_%f,%f,%f %f %d %d %d,%d %d\n",
MapName,
ModelInstName,
(float) pos.x, (float) pos.y, (float) pos.z,
(float) rot.x, (float) rot.y, (float) rot.z,
sc,
nVertices,
realx1, realy1,
realx2, realy2
); */
}

View File

@@ -0,0 +1,66 @@
/*
* Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MODEL_H
#define MODEL_H
#include "vec3d.h"
#include "modelheaders.h"
#include <vector>
class MPQFile;
Vec3D fixCoordSystem(Vec3D v);
class Model
{
private:
void _unload()
{
delete[] vertices;
delete[] indices;
vertices = NULL;
indices = NULL;
}
std::string filename;
public:
ModelHeader header;
Vec3D* vertices;
uint16* indices;
bool open();
bool ConvertToVMAPModel(char const* outfilename);
Model(std::string& filename);
~Model() { _unload(); }
};
class ModelInstance
{
public:
uint32 id;
Vec3D pos, rot;
uint16 scale, flags;
float sc;
ModelInstance() : id(0), scale(0), flags(0), sc(0.0f) {}
ModelInstance(MPQFile& f, char const* ModelInstName, uint32 mapID, uint32 tileX, uint32 tileY, FILE* pDirfile);
};
#endif

View File

@@ -0,0 +1,94 @@
/*
* Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MODELHEADERS_H
#define MODELHEADERS_H
#include "mpqfile.h" // integer typedefs
#pragma pack(push,1)
struct ModelHeader
{
char id[4];
uint8 version[4];
uint32 nameLength;
uint32 nameOfs;
uint32 type;
uint32 nGlobalSequences;
uint32 ofsGlobalSequences;
uint32 nAnimations;
uint32 ofsAnimations;
uint32 nAnimationLookup;
uint32 ofsAnimationLookup;
uint32 nBones;
uint32 ofsBones;
uint32 nKeyBoneLookup;
uint32 ofsKeyBoneLookup;
uint32 nVertices;
uint32 ofsVertices;
uint32 nViews;
uint32 nColors;
uint32 ofsColors;
uint32 nTextures;
uint32 ofsTextures;
uint32 nTransparency;
uint32 ofsTransparency;
uint32 nTextureanimations;
uint32 ofsTextureanimations;
uint32 nTexReplace;
uint32 ofsTexReplace;
uint32 nRenderFlags;
uint32 ofsRenderFlags;
uint32 nBoneLookupTable;
uint32 ofsBoneLookupTable;
uint32 nTexLookup;
uint32 ofsTexLookup;
uint32 nTexUnits;
uint32 ofsTexUnits;
uint32 nTransLookup;
uint32 ofsTransLookup;
uint32 nTexAnimLookup;
uint32 ofsTexAnimLookup;
float floats[14];
uint32 nBoundingTriangles;
uint32 ofsBoundingTriangles;
uint32 nBoundingVertices;
uint32 ofsBoundingVertices;
uint32 nBoundingNormals;
uint32 ofsBoundingNormals;
uint32 nAttachments;
uint32 ofsAttachments;
uint32 nAttachLookup;
uint32 ofsAttachLookup;
uint32 nAttachments_2;
uint32 ofsAttachments_2;
uint32 nLights;
uint32 ofsLights;
uint32 nCameras;
uint32 ofsCameras;
uint32 nCameraLookup;
uint32 ofsCameraLookup;
uint32 nRibbonEmitters;
uint32 ofsRibbonEmitters;
uint32 nParticleEmitters;
uint32 ofsParticleEmitters;
};
#pragma pack(pop)
#endif

View File

@@ -0,0 +1,79 @@
#include "mpqfile.h"
#include <deque>
#include <cstdio>
MPQFile::MPQFile(const char* filename) :
eof(false),
buffer(0),
pointer(0),
size(0)
{
FILE* f = fopen(filename, "rb");
if (!f)
{
// fprintf(stderr, "Can't open %s\n", filename);
eof = true;
return;
}
fseek(f, 0, SEEK_END);
size_t sizeTemp = ftell(f);
size = sizeTemp;
rewind(f);
if (size <= 1)
{
fprintf(stderr, "Can't open %s, size = %u!\n", filename, uint32(size));
fclose(f);
eof = true;
return;
}
buffer = new char[size];
if (fread(buffer, sizeTemp, 1, f) != 1)
{
fprintf(stderr, "Can't read %s, size=%u!\n", filename, uint32(size));
fclose(f);
eof = true;
return;
}
size = sizeTemp;
fclose(f);
}
size_t MPQFile::read(void* dest, size_t bytes)
{
if (eof) return 0;
size_t rpos = pointer + bytes;
if (rpos > size) {
bytes = size - pointer;
eof = true;
}
memcpy(dest, &(buffer[pointer]), bytes);
pointer = rpos;
return bytes;
}
void MPQFile::seek(int offset)
{
pointer = offset;
eof = (pointer >= size);
}
void MPQFile::seekRelative(int offset)
{
pointer += offset;
eof = (pointer >= size);
}
void MPQFile::close()
{
if (buffer) delete[] buffer;
buffer = 0;
eof = true;
}

View File

@@ -0,0 +1,67 @@
#define _CRT_SECURE_NO_DEPRECATE
#ifndef _CRT_SECURE_NO_WARNINGS // fuck the police^Wwarnings
#define _CRT_SECURE_NO_WARNINGS
#endif
#ifndef MPQ_H
#define MPQ_H
#include <string.h>
#include <ctype.h>
#include <vector>
#include <iostream>
#include <deque>
#include <cstdint>
typedef int64_t int64;
typedef int32_t int32;
typedef int16_t int16;
typedef int8_t int8;
typedef uint64_t uint64;
typedef uint32_t uint32;
typedef uint16_t uint16;
typedef uint8_t uint8;
#ifdef _WIN32
#include <Windows.h> // mainly only HANDLE definition is required
#else
int GetLastError();
#endif
class MPQFile
{
//MPQHANDLE handle;
bool eof;
char *buffer;
size_t pointer,size;
// disable copying
MPQFile(const MPQFile &f);
void operator=(const MPQFile &f);
public:
MPQFile(const char* filename); // filenames are not case sensitive
~MPQFile() { close(); }
size_t read(void* dest, size_t bytes);
size_t getSize() { return size; }
size_t getPos() { return pointer; }
char* getBuffer() { return buffer; }
char* getPointer() { return buffer + pointer; }
bool isEof() { return eof; }
void seek(int offset);
void seekRelative(int offset);
void close();
};
inline void flipcc(char *fcc)
{
char t;
t=fcc[0];
fcc[0]=fcc[3];
fcc[3]=t;
t=fcc[1];
fcc[1]=fcc[2];
fcc[2]=t;
}
#endif

View File

@@ -0,0 +1,248 @@
/*
* Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef VEC3D_H
#define VEC3D_H
#include <iostream>
#include <cmath>
class Vec3D
{
public:
float x,y,z;
Vec3D(float x0 = 0.0f, float y0 = 0.0f, float z0 = 0.0f) : x(x0), y(y0), z(z0) {}
Vec3D(const Vec3D& v) : x(v.x), y(v.y), z(v.z) {}
Vec3D& operator= (const Vec3D &v) {
x = v.x;
y = v.y;
z = v.z;
return *this;
}
Vec3D operator+ (const Vec3D &v) const
{
Vec3D r(x+v.x,y+v.y,z+v.z);
return r;
}
Vec3D operator- (const Vec3D &v) const
{
Vec3D r(x-v.x,y-v.y,z-v.z);
return r;
}
float operator* (const Vec3D &v) const
{
return x*v.x + y*v.y + z*v.z;
}
Vec3D operator* (float d) const
{
Vec3D r(x*d,y*d,z*d);
return r;
}
friend Vec3D operator* (float d, const Vec3D& v)
{
return v * d;
}
Vec3D operator% (const Vec3D &v) const
{
Vec3D r(y*v.z-z*v.y, z*v.x-x*v.z, x*v.y-y*v.x);
return r;
}
Vec3D& operator+= (const Vec3D &v)
{
x += v.x;
y += v.y;
z += v.z;
return *this;
}
Vec3D& operator-= (const Vec3D &v)
{
x -= v.x;
y -= v.y;
z -= v.z;
return *this;
}
Vec3D& operator*= (float d)
{
x *= d;
y *= d;
z *= d;
return *this;
}
float lengthSquared() const
{
return x*x+y*y+z*z;
}
float length() const
{
return std::sqrt(x*x+y*y+z*z);
}
Vec3D& normalize()
{
this->operator*= (1.0f/length());
return *this;
}
Vec3D operator~ () const
{
Vec3D r(*this);
r.normalize();
return r;
}
friend std::istream& operator>>(std::istream& in, Vec3D& v)
{
in >> v.x >> v.y >> v.z;
return in;
}
friend std::ostream& operator<<(std::ostream& out, const Vec3D& v)
{
out << v.x << " " << v.y << " " << v.z;
return out;
}
operator float*()
{
return (float*)this;
}
};
class Vec2D
{
public:
float x,y;
Vec2D(float x0 = 0.0f, float y0 = 0.0f) : x(x0), y(y0) {}
Vec2D(const Vec2D& v) : x(v.x), y(v.y) {}
Vec2D& operator= (const Vec2D &v) {
x = v.x;
y = v.y;
return *this;
}
Vec2D operator+ (const Vec2D &v) const
{
Vec2D r(x+v.x,y+v.y);
return r;
}
Vec2D operator- (const Vec2D &v) const
{
Vec2D r(x-v.x,y-v.y);
return r;
}
float operator* (const Vec2D &v) const
{
return x*v.x + y*v.y;
}
Vec2D operator* (float d) const
{
Vec2D r(x*d,y*d);
return r;
}
friend Vec2D operator* (float d, const Vec2D& v)
{
return v * d;
}
Vec2D& operator+= (const Vec2D &v)
{
x += v.x;
y += v.y;
return *this;
}
Vec2D& operator-= (const Vec2D &v)
{
x -= v.x;
y -= v.y;
return *this;
}
Vec2D& operator*= (float d)
{
x *= d;
y *= d;
return *this;
}
float lengthSquared() const
{
return x*x+y*y;
}
float length() const
{
return std::sqrt(x*x+y*y);
}
Vec2D& normalize()
{
this->operator*= (1.0f/length());
return *this;
}
Vec2D operator~ () const
{
Vec2D r(*this);
r.normalize();
return r;
}
friend std::istream& operator>>(std::istream& in, Vec2D& v)
{
in >> v.x >> v.y;
return in;
}
operator float*()
{
return (float*)this;
}
};
inline void rotate(float x0, float y0, float *x, float *y, float angle)
{
float xa = *x - x0, ya = *y - y0;
*x = xa*cosf(angle) - ya*sinf(angle) + x0;
*y = xa*sinf(angle) + ya*cosf(angle) + y0;
}
#endif

View File

@@ -0,0 +1,417 @@
/*
* Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define _CRT_SECURE_NO_DEPRECATE
#include <cstdio>
#include <iostream>
#include <vector>
#include <list>
#include <errno.h>
#ifdef WIN32
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <sys/stat.h>
#include <direct.h>
#define mkdir _mkdir
#else
#include <sys/stat.h>
#define ERROR_PATH_NOT_FOUND ERROR_FILE_NOT_FOUND
#endif
#include <map>
#include <fstream>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
//From Extractor
#include "adtfile.h"
#include "wdtfile.h"
#include "dbcfile.h"
#include "wmo.h"
#include "Common.h"
#include "vmapexport.h"
typedef struct
{
char name[64];
unsigned int id;
}map_id;
map_id * map_ids;
uint16 *LiqType = 0;
uint32 map_count;
char output_path[128] = ".";
char input_path[1024] = ".";
bool preciseVectorData = false;
// Constants
//static const char * szWorkDirMaps = ".\\Maps";
const char* szWorkDirWmo = "./Buildings";
const char* szRawVMAPMagic = "VMAP043";
// Local testing functions
bool FileExists(const char* file)
{
if (FILE* n = fopen(file, "rb"))
{
fclose(n);
return true;
}
return false;
}
void strToLower(char* str)
{
while (*str)
{
*str = tolower(*str);
++str;
}
}
// copied from contrib/extractor/System.cpp
void LoadLiquidTypeDB2Data()
{
printf("Read LiquidType.db2 file...");
DBCFile dbc("DBFilesClient\\LiquidType.db2", "nsifffffssssssiiffffffffffffffffffiiiittbbbbbbbbbbi");
if (!dbc.open())
{
printf("Fatal error: Invalid LiquidType.db2 file format!\n");
exit(1);
}
size_t LiqType_count = dbc.getRecordCount();
size_t LiqType_maxid = dbc.getRecord(LiqType_count - 1).getUInt(0);
LiqType = new uint16[LiqType_maxid + 1];
memset(LiqType, 0xff, (LiqType_maxid + 1) * sizeof(uint16));
for (uint32 x = 0; x < LiqType_count; ++x)
LiqType[dbc.getRecord(x).getUInt(0)] = dbc.getRecord(x).getUInt8(40);
printf("Done! (%u LiqTypes loaded)\n", (unsigned int)LiqType_count);
}
bool ExtractWmo()
{
bool success = true;
std::ifstream wmoList("wmo_list.txt");
if (!wmoList)
{
printf("\nUnable to open wmo_list.txt! Nothing extracted.\n");
return false;
}
std::set<std::string> wmos;
for (;;)
{
std::string str;
std::getline(wmoList, str);
if (str.empty())
break;
wmos.insert(std::move(str));
}
for (std::string str : wmos)
success &= ExtractSingleWmo(str);
if (success)
printf("\nExtract wmo complete (No (fatal) errors)\n");
return success;
}
bool ExtractSingleWmo(std::string& fname)
{
// Copy files from archive
char szLocalFile[1024];
const char * plain_name = GetPlainName(fname.c_str());
sprintf(szLocalFile, "%s/%s", szWorkDirWmo, plain_name);
FixNameCase(szLocalFile, strlen(szLocalFile));
if (FileExists(szLocalFile))
return true;
int p = 0;
// Select root wmo files
char const* rchr = strrchr(plain_name, '_');
if (rchr != NULL)
{
char cpy[4];
memcpy(cpy, rchr, 4);
for (int i = 0; i < 4; ++i)
{
int m = cpy[i];
if (isdigit(m))
p++;
}
}
if (p == 3)
return true;
bool file_ok = true;
std::cout << "Extracting " << fname << std::endl;
WMORoot froot(fname);
if (!froot.open())
{
printf("Couldn't open RootWmo!!!\n");
return true;
}
FILE *output = fopen(szLocalFile, "wb");
if (!output)
{
printf("couldn't open %s for writing!\n", szLocalFile);
return false;
}
froot.ConvertToVMAPRootWmo(output);
int Wmo_nVertices = 0;
//printf("root has %d groups\n", froot->nGroups);
if (froot.nGroups != 0)
{
for (uint32 i = 0; i < froot.nGroups; ++i)
{
char temp[1024];
strncpy(temp, fname.c_str(), 1024);
temp[fname.length() - 4] = 0;
char groupFileName[1024];
sprintf(groupFileName, "%s_%03u.wmo", temp, i);
//printf("Trying to open groupfile %s\n",groupFileName);
std::string s = groupFileName;
WMOGroup fgroup(s);
if (!fgroup.open())
{
printf("Could not open all Group file for: %s\n", plain_name);
file_ok = false;
break;
}
Wmo_nVertices += fgroup.ConvertToVMAPGroupWmo(output, &froot, preciseVectorData);
}
}
fseek(output, 8, SEEK_SET); // store the correct no of vertices
fwrite(&Wmo_nVertices, sizeof(int), 1, output);
fclose(output);
// Delete the extracted file in the case of an error
if (!file_ok)
remove(szLocalFile);
return true;
}
void ParsMapFiles()
{
char fn[512];
//char id_filename[64];
char id[10];
for (unsigned int i = 0; i < map_count; ++i)
{
sprintf(id, "%04u", map_ids[i].id);
sprintf(fn, "World\\Maps\\%s\\%s.wdt", map_ids[i].name, map_ids[i].name);
WDTFile WDT(fn, map_ids[i].name);
if (WDT.init(id, map_ids[i].id))
{
printf("Processing Map %u\n[", map_ids[i].id);
for (int x = 0; x < 64; ++x)
{
for (int y = 0; y < 64; ++y)
{
if (ADTFile *ADT = WDT.GetMap(x, y))
{
//sprintf(id_filename,"%02u %02u %03u",x,y,map_ids[i].id);//!!!!!!!!!
ADT->init(map_ids[i].id, x, y);
delete ADT;
}
}
printf("#");
fflush(stdout);
}
printf("]\n");
}
}
}
void getGamePath()
{
#ifdef _WIN32
strcpy(input_path, "Data\\");
#else
strcpy(input_path,"Data/");
#endif
}
bool processArgv(int argc, char ** argv, const char *versionString)
{
bool result = true;
bool hasInputPathParam = false;
preciseVectorData = false;
for (int i = 1; i < argc; ++i)
{
if (strcmp("-s", argv[i]) == 0)
{
preciseVectorData = false;
}
else if (strcmp("-d", argv[i]) == 0)
{
if ((i + 1) < argc)
{
hasInputPathParam = true;
strncpy(input_path, argv[i + 1], sizeof(input_path));
input_path[sizeof(input_path) - 1] = '\0';
if (input_path[strlen(input_path) - 1] != '\\' && input_path[strlen(input_path) - 1] != '/')
strcat(input_path, "/");
++i;
}
else
{
result = false;
}
}
else if (strcmp("-?", argv[1]) == 0)
{
result = false;
}
else if (strcmp("-l", argv[i]) == 0)
{
preciseVectorData = true;
}
else
{
result = false;
break;
}
}
if (!result)
{
printf("Extract %s.\n", versionString);
printf("%s [-?][-s][-l][-d <path>]\n", argv[0]);
printf(" -s : (default) small size (data size optimization), ~500MB less vmap data.\n");
printf(" -l : large size, ~500MB more vmap data. (might contain more details)\n");
printf(" -d <path>: Path to the vector data source folder.\n");
printf(" -? : This message.\n");
}
if (!hasInputPathParam)
getGamePath();
return result;
}
int main(int argc, char ** argv)
{
bool success = true;
const char *versionString = "V4.03 2015_05";
// Use command line arguments, when some
if (!processArgv(argc, argv, versionString))
return 1;
// some simple check if working dir is dirty
else
{
std::string sdir = std::string(szWorkDirWmo) + "/dir";
std::string sdir_bin = std::string(szWorkDirWmo) + "/dir_bin";
struct stat status;
if (!stat(sdir.c_str(), &status) || !stat(sdir_bin.c_str(), &status))
{
printf("Your output directory seems to be polluted, please use an empty directory!\n");
printf("<press return to exit>");
char garbage[2];
return scanf("%c", garbage);
}
}
printf("Extract %s. Beginning work ....\n\n", versionString);
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
// Create the working directory
if (mkdir(szWorkDirWmo
#if defined(__linux__) || defined(__APPLE__)
, 0711
#endif
))
success = (errno == EEXIST);
// Extract models, listed in GameObjectDisplayInfo.db2
ExtractGameobjectModels();
LoadLiquidTypeDB2Data();
// extract data
if (success)
success = ExtractWmo();
//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
//map.dbc
if (success)
{
printf("Read Map.db2 file...\n");
DBCFile * dbc = new DBCFile("DBFilesClient\\Map.db2", "nsiifffsssttttttbbbbb");
if (!dbc->open())
{
printf("Fatal error: Invalid Map.db2 file format!\n");
exit(1);
}
map_count = dbc->getRecordCount();
map_ids = new map_id[map_count];
for (unsigned int x = 0; x < map_count; ++x)
{
map_ids[x].id = dbc->getRecord(x).getUInt(0);
const char* map_name = dbc->getRecord(x).getString(1);
size_t max_map_name_length = sizeof(map_ids[x].name);
if (strlen(map_name) >= max_map_name_length)
{
delete dbc;
delete[] map_ids;
printf("FATAL ERROR: Map name too long.\n");
return 1;
}
strncpy(map_ids[x].name, map_name, max_map_name_length);
map_ids[x].name[max_map_name_length - 1] = '\0';
printf("Map - %s\n", map_ids[x].name);
}
delete dbc;
ParsMapFiles();
delete[] map_ids;
}
printf("\n");
if (!success)
{
printf("ERROR: Extract %s. Work NOT complete.\n Precise vector data=%d.\nPress any key.\n", versionString, preciseVectorData);
getchar();
}
printf("Extract %s. Work complete. No errors.\n", versionString);
delete[] LiqType;
return 0;
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef VMAPEXPORT_H
#define VMAPEXPORT_H
#include <string>
enum ModelFlags
{
MOD_M2 = 1,
MOD_WORLDSPAWN = 1<<1,
MOD_HAS_BOUND = 1<<2
};
extern const char * szWorkDirWmo;
extern const char * szRawVMAPMagic; // vmap magic string for extracted raw vmap data
bool FileExists(const char * file);
void strToLower(char* str);
bool ExtractSingleWmo(std::string& fname);
bool ExtractSingleModel(std::string& fname);
void ExtractGameobjectModels();
#endif

View File

@@ -0,0 +1,118 @@
/*
* Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "vmapexport.h"
#include "wdtfile.h"
#include "adtfile.h"
#include <cstdio>
char * wdtGetPlainName(char * FileName)
{
char * szTemp;
if((szTemp = strrchr(FileName, '\\')) != NULL)
FileName = szTemp + 1;
return FileName;
}
WDTFile::WDTFile(char* file_name, char* file_name1):WDT(file_name), gnWMO(0)
{
filename.append(file_name1,strlen(file_name1));
}
bool WDTFile::init(char* /*map_id*/, unsigned int mapID)
{
if (WDT.isEof())
return false;
char fourcc[5];
uint32 size;
std::string dirname = std::string(szWorkDirWmo) + "/dir_bin";
FILE *dirfile;
dirfile = fopen(dirname.c_str(), "ab");
if(!dirfile)
{
// printf("Can't open dirfile!'%s'\n", dirname.c_str());
return false;
}
while (!WDT.isEof())
{
WDT.read(fourcc,4);
WDT.read(&size, 4);
flipcc(fourcc);
fourcc[4] = 0;
size_t nextpos = WDT.getPos() + size;
if (!strcmp(fourcc,"MAIN")) { }
if (!strcmp(fourcc,"MWMO"))
{
if (!size)
break;
char *buf = new char[size];
WDT.read(buf, size);
char *p = buf;
while (p < buf + size)
{
char* s = wdtGetPlainName(p);
FixNameCase(s, strlen(s));
p = p + strlen(p) + 1;
gWmoInstansName.push_back(s);
}
delete[] buf;
}
else if (!strcmp(fourcc, "MODF")) // changed on legion
{
if (!size)
break;
gnWMO = (int)size / 64;
for (int i = 0; i < gnWMO; ++i)
{
int id;
WDT.read(&id, 4);
WMOInstance inst(WDT, gWmoInstansName[id].c_str(), mapID, 65, 65, dirfile);
}
}
WDT.seek((int)nextpos);
}
WDT.close();
fclose(dirfile);
return true;
}
WDTFile::~WDTFile(void)
{
WDT.close();
}
ADTFile* WDTFile::GetMap(int x, int z)
{
if (!(x >= 0 && z >= 0 && x < 64 && z < 64))
return NULL;
char name[512];
sprintf(name, "World\\Maps\\%s\\%s_%d_%d_obj0.adt", filename.c_str(), filename.c_str(), x, z);
return new ADTFile(name);
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef WDTFILE_H
#define WDTFILE_H
#include "mpqfile.h"
#include "wmo.h"
#include <string>
#include <vector>
#include <cstdlib>
class ADTFile;
class WDTFile
{
private:
MPQFile WDT;
std::string filename;
public:
WDTFile(char* file_name, char* file_name1);
~WDTFile(void);
bool init(char* map_id, unsigned int mapID);
std::vector<std::string> gWmoInstansName;
int gnWMO;
ADTFile* GetMap(int x, int z);
};
#endif

View File

@@ -0,0 +1,573 @@
/*
* Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "vmapexport.h"
#include "wmo.h"
#include "vec3d.h"
#include <cstdio>
#include <cstdlib>
#include <cassert>
#include <map>
#include <fstream>
#undef min
#undef max
#include "mpqfile.h"
using namespace std;
extern uint16 *LiqType;
WMORoot::WMORoot(std::string &filename)
: filename(filename), col(0), nTextures(0), nGroups(0), nP(0), nLights(0),
nModels(0), nDoodads(0), nDoodadSets(0), RootWMOID(0), liquidType(0)
{
memset(bbcorn1, 0, sizeof(bbcorn1));
memset(bbcorn2, 0, sizeof(bbcorn2));
}
bool WMORoot::open()
{
MPQFile f(filename.c_str());
if(f.isEof ())
{
printf("No such file.\n");
return false;
}
uint32 size;
char fourcc[5];
while (!f.isEof())
{
f.read(fourcc,4);
f.read(&size, 4);
flipcc(fourcc);
fourcc[4] = 0;
size_t nextpos = f.getPos() + size;
if (!strcmp(fourcc,"MOHD")) // header
{
f.read(&nTextures, 4);
f.read(&nGroups, 4);
f.read(&nP, 4);
f.read(&nLights, 4);
f.read(&nModels, 4);
f.read(&nDoodads, 4);
f.read(&nDoodadSets, 4);
f.read(&col, 4);
f.read(&RootWMOID, 4);
f.read(bbcorn1, 12);
f.read(bbcorn2, 12);
f.read(&liquidType, 4);
f.read(&flagHasSomeOutdoorGroup, 4);
f.read(&FlagLod, 4);
f.read(&Unk, 4);
break;
}
/*
else if (!strcmp(fourcc,"MOTX"))
{
}
else if (!strcmp(fourcc,"MOMT"))
{
}
else if (!strcmp(fourcc,"MOGN"))
{
}
else if (!strcmp(fourcc,"MOGI"))
{
}
else if (!strcmp(fourcc,"MOLT"))
{
}
else if (!strcmp(fourcc,"MODN"))
{
}
else if (!strcmp(fourcc,"MODS"))
{
}
else if (!strcmp(fourcc,"MODD"))
{
}
else if (!strcmp(fourcc,"MOSB"))
{
}
else if (!strcmp(fourcc,"MOPV"))
{
}
else if (!strcmp(fourcc,"MOPT"))
{
}
else if (!strcmp(fourcc,"MOPR"))
{
}
else if (!strcmp(fourcc,"MFOG"))
{
}
*/
f.seek((int)nextpos);
}
f.close ();
return true;
}
bool WMORoot::ConvertToVMAPRootWmo(FILE* pOutfile)
{
//printf("Convert RootWmo...\n");
fwrite(szRawVMAPMagic, 1, 8, pOutfile);
unsigned int nVectors = 0;
fwrite(&nVectors,sizeof(nVectors), 1, pOutfile); // will be filled later
fwrite(&nGroups, 4, 1, pOutfile);
fwrite(&RootWMOID, 4, 1, pOutfile);
return true;
}
WMOGroup::WMOGroup(const std::string &filename) :
filename(filename), MOPY(0), MOVI(0), MoviEx(0), MOVT(0), MOBA(0), MobaEx(0),
hlq(0), LiquEx(0), LiquBytes(0), groupName(0), descGroupName(0), mogpFlags(0),
moprIdx(0), moprNItems(0), nBatchA(0), nBatchB(0), nBatchC(0), fogIdx(0),
liquidType(0), groupWMOID(0), mopy_size(0), moba_size(0), LiquEx_size(0),
nVertices(0), nTriangles(0), liquflags(0)
{
memset(bbcorn1, 0, sizeof(bbcorn1));
memset(bbcorn2, 0, sizeof(bbcorn2));
}
bool WMOGroup::open()
{
MPQFile f(filename.c_str());
if(f.isEof ())
{
printf("No such file.\n");
return false;
}
uint32 size;
char fourcc[5];
while (!f.isEof())
{
f.read(fourcc,4);
f.read(&size, 4);
flipcc(fourcc);
if (!strcmp(fourcc,"MOGP"))//Fix sizeoff = Data size.
{
size = 68;
}
fourcc[4] = 0;
size_t nextpos = f.getPos() + size;
LiquEx_size = 0;
liquflags = 0;
if (!strcmp(fourcc,"MOGP"))//header
{
f.read(&groupName, 4);
f.read(&descGroupName, 4);
f.read(&mogpFlags, 4);
f.read(bbcorn1, 12);
f.read(bbcorn2, 12);
f.read(&moprIdx, 2);
f.read(&moprNItems, 2);
f.read(&nBatchA, 2);
f.read(&nBatchB, 2);
f.read(&nBatchC, 4);
f.read(&fogIdx, 4);
f.read(&liquidType, 4);
f.read(&groupWMOID,4);
f.read(&CanCutTerrain, 4);
f.read(&Unused, 4);
}
else if (!strcmp(fourcc,"MOPY"))
{
MOPY = new char[size];
mopy_size = size;
nTriangles = (int)size / 2;
f.read(MOPY, size);
}
else if (!strcmp(fourcc,"MOVI"))
{
MOVI = new uint16[size/2];
f.read(MOVI, size);
}
else if (!strcmp(fourcc,"MOVT"))
{
MOVT = new float[size/4];
f.read(MOVT, size);
nVertices = (int)size / 12;
}
else if (!strcmp(fourcc,"MONR"))
{
}
else if (!strcmp(fourcc,"MOTV"))
{
}
else if (!strcmp(fourcc,"MOBA"))
{
MOBA = new uint16[size/2];
moba_size = size/2;
f.read(MOBA, size);
}
else if (!strcmp(fourcc,"MLIQ"))
{
liquflags |= 1;
hlq = new WMOLiquidHeader();
f.read(hlq, 0x1E);
LiquEx_size = sizeof(WMOLiquidVert) * hlq->xverts * hlq->yverts;
LiquEx = new WMOLiquidVert[hlq->xverts * hlq->yverts];
f.read(LiquEx, LiquEx_size);
int nLiquBytes = hlq->xtiles * hlq->ytiles;
LiquBytes = new char[nLiquBytes];
f.read(LiquBytes, nLiquBytes);
/* std::ofstream llog("Buildings/liquid.log", ios_base::out | ios_base::app);
llog << filename;
llog << "\nbbox: " << bbcorn1[0] << ", " << bbcorn1[1] << ", " << bbcorn1[2] << " | " << bbcorn2[0] << ", " << bbcorn2[1] << ", " << bbcorn2[2];
llog << "\nlpos: " << hlq->pos_x << ", " << hlq->pos_y << ", " << hlq->pos_z;
llog << "\nx-/yvert: " << hlq->xverts << "/" << hlq->yverts << " size: " << size << " expected size: " << 30 + hlq->xverts*hlq->yverts*8 + hlq->xtiles*hlq->ytiles << std::endl;
llog.close(); */
}
f.seek((int)nextpos);
}
f.close();
return true;
}
int WMOGroup::ConvertToVMAPGroupWmo(FILE *output, WMORoot *rootWMO, bool preciseVectorData)
{
fwrite(&mogpFlags,sizeof(uint32),1,output);
fwrite(&groupWMOID,sizeof(uint32),1,output);
// group bound
fwrite(bbcorn1, sizeof(float), 3, output);
fwrite(bbcorn2, sizeof(float), 3, output);
fwrite(&liquflags,sizeof(uint32),1,output);
int nColTriangles = 0;
if (preciseVectorData)
{
char GRP[] = "GRP ";
fwrite(GRP,1,4,output);
int k = 0;
int moba_batch = moba_size/12;
MobaEx = new int[moba_batch*4];
for(int i=8; i<moba_size; i+=12)
{
MobaEx[k++] = MOBA[i];
}
int moba_size_grp = moba_batch*4+4;
fwrite(&moba_size_grp,4,1,output);
fwrite(&moba_batch,4,1,output);
fwrite(MobaEx,4,k,output);
delete [] MobaEx;
uint32 nIdexes = nTriangles * 3;
if(fwrite("INDX",4, 1, output) != 1)
{
printf("Error while writing file nbraches ID");
exit(0);
}
int wsize = sizeof(uint32) + sizeof(unsigned short) * nIdexes;
if(fwrite(&wsize, sizeof(int), 1, output) != 1)
{
printf("Error while writing file wsize");
// no need to exit?
}
if(fwrite(&nIdexes, sizeof(uint32), 1, output) != 1)
{
printf("Error while writing file nIndexes");
exit(0);
}
if(nIdexes >0)
{
if(fwrite(MOVI, sizeof(unsigned short), nIdexes, output) != nIdexes)
{
printf("Error while writing file indexarray");
exit(0);
}
}
if(fwrite("VERT",4, 1, output) != 1)
{
printf("Error while writing file nbraches ID");
exit(0);
}
wsize = sizeof(int) + sizeof(float) * 3 * nVertices;
if(fwrite(&wsize, sizeof(int), 1, output) != 1)
{
printf("Error while writing file wsize");
// no need to exit?
}
if(fwrite(&nVertices, sizeof(int), 1, output) != 1)
{
printf("Error while writing file nVertices");
exit(0);
}
if(nVertices >0)
{
if(fwrite(MOVT, sizeof(float)*3, nVertices, output) != nVertices)
{
printf("Error while writing file vectors");
exit(0);
}
}
nColTriangles = nTriangles;
}
else
{
char GRP[] = "GRP ";
fwrite(GRP,1,4,output);
int k = 0;
int moba_batch = moba_size/12;
MobaEx = new int[moba_batch*4];
for(int i=8; i<moba_size; i+=12)
{
MobaEx[k++] = MOBA[i];
}
int moba_size_grp = moba_batch*4+4;
fwrite(&moba_size_grp,4,1,output);
fwrite(&moba_batch,4,1,output);
fwrite(MobaEx,4,k,output);
delete [] MobaEx;
//-------INDX------------------------------------
//-------MOPY--------
MoviEx = new uint16[nTriangles*3]; // "worst case" size...
int *IndexRenum = new int[nVertices];
memset(IndexRenum, 0xFF, nVertices*sizeof(int));
for (int i=0; i<nTriangles; ++i)
{
// Skip no collision triangles
if (MOPY[2*i]&WMO_MATERIAL_NO_COLLISION ||
!(MOPY[2*i]&(WMO_MATERIAL_HINT|WMO_MATERIAL_COLLIDE_HIT)) )
continue;
// Use this triangle
for (int j=0; j<3; ++j)
{
IndexRenum[MOVI[3*i + j]] = 1;
MoviEx[3*nColTriangles + j] = MOVI[3*i + j];
}
++nColTriangles;
}
// assign new vertex index numbers
int nColVertices = 0;
for (uint32 i=0; i<nVertices; ++i)
{
if (IndexRenum[i] == 1)
{
IndexRenum[i] = nColVertices;
++nColVertices;
}
}
// translate triangle indices to new numbers
for (int i=0; i<3*nColTriangles; ++i)
{
assert(MoviEx[i] < nVertices);
MoviEx[i] = IndexRenum[MoviEx[i]];
}
// write triangle indices
int INDX[] = {0x58444E49, nColTriangles*6+4, nColTriangles*3};
fwrite(INDX,4,3,output);
fwrite(MoviEx,2,nColTriangles*3,output);
// write vertices
int VERT[] = {0x54524556, nColVertices*3*static_cast<int>(sizeof(float))+4, nColVertices};// "VERT"
int check = 3*nColVertices;
fwrite(VERT,4,3,output);
for (uint32 i=0; i<nVertices; ++i)
if(IndexRenum[i] >= 0)
check -= fwrite(MOVT+3*i, sizeof(float), 3, output);
assert(check==0);
delete [] MoviEx;
delete [] IndexRenum;
}
//------LIQU------------------------
if (LiquEx_size != 0)
{
int LIQU_h[] = {0x5551494C, static_cast<int>(sizeof(WMOLiquidHeader) + LiquEx_size) + hlq->xtiles*hlq->ytiles};// "LIQU"
fwrite(LIQU_h, 4, 2, output);
// according to WoW.Dev Wiki:
uint32 liquidEntry;
if (rootWMO->liquidType & 4)
liquidEntry = liquidType;
else if (liquidType == 15)
liquidEntry = 0;
else
liquidEntry = liquidType + 1;
if (!liquidEntry)
{
int v1; // edx@1
int v2; // eax@1
v1 = hlq->xtiles * hlq->ytiles;
v2 = 0;
if (v1 > 0)
{
while ((LiquBytes[v2] & 0xF) == 15)
{
++v2;
if (v2 >= v1)
break;
}
if (v2 < v1 && (LiquBytes[v2] & 0xF) != 15)
liquidEntry = (LiquBytes[v2] & 0xF) + 1;
}
}
if (liquidEntry && liquidEntry < 21)
{
switch ((liquidEntry - 1) & 3)
{
case 0:
liquidEntry = ((mogpFlags & 0x80000) != 0) + 13;
break;
case 1:
liquidEntry = 14;
break;
case 2:
liquidEntry = 19;
break;
case 3:
liquidEntry = 20;
break;
}
}
hlq->type = liquidEntry;
/* std::ofstream llog("Buildings/liquid.log", ios_base::out | ios_base::app);
llog << filename;
llog << ":\nliquidEntry: " << liquidEntry << " type: " << hlq->type << " (root:" << rootWMO->liquidType << " group:" << liquidType << ")\n";
llog.close(); */
fwrite(hlq, sizeof(WMOLiquidHeader), 1, output);
// only need height values, the other values are unknown anyway
for (uint32 i = 0; i<LiquEx_size/sizeof(WMOLiquidVert); ++i)
fwrite(&LiquEx[i].height, sizeof(float), 1, output);
// todo: compress to bit field
fwrite(LiquBytes, 1, hlq->xtiles*hlq->ytiles, output);
}
return nColTriangles;
}
WMOGroup::~WMOGroup()
{
delete [] MOPY;
delete [] MOVI;
delete [] MOVT;
delete [] MOBA;
delete hlq;
delete [] LiquEx;
delete [] LiquBytes;
}
WMOInstance::WMOInstance(MPQFile& f, char const* WmoInstName, uint32 mapID, uint32 tileX, uint32 tileY, FILE* pDirfile)
: currx(0), curry(0), wmo(NULL), doodadset(0), pos(), indx(0), id(0), d2(0), d3(0)
{
float ff[3];
f.read(&id, 4);
f.read(ff,12);
pos = Vec3D(ff[0],ff[1],ff[2]);
f.read(ff,12);
rot = Vec3D(ff[0],ff[1],ff[2]);
f.read(ff,12);
pos2 = Vec3D(ff[0],ff[1],ff[2]);
f.read(ff,12);
pos3 = Vec3D(ff[0],ff[1],ff[2]);
f.read(&d2,4); //flags + doodadSet
uint16 trash,adtId;
f.read(&adtId, 2); //nameSet
f.read(&trash, 2); //unk
//-----------add_in _dir_file----------------
char tempname[512];
sprintf(tempname, "%s/%s", szWorkDirWmo, WmoInstName);
FILE *input;
input = fopen(tempname, "r+b");
if(!input)
{
// printf("WMOInstance::WMOInstance: couldn't open %s\n", tempname);
//system("pause");
return;
}
// printf("WMOInstance::open %s\n", tempname);
fseek(input, 8, SEEK_SET); // get the correct no of vertices
int nVertices;
int count = fread(&nVertices, sizeof (int), 1, input);
fclose(input);
if (count != 1 || nVertices == 0)
return;
float x,z;
x = pos.x;
z = pos.z;
if(x==0 && z == 0)
{
pos.x = 533.33333f*32;
pos.z = 533.33333f*32;
}
pos = fixCoords(pos);
pos2 = fixCoords(pos2);
pos3 = fixCoords(pos3);
float scale = 1.0f;
uint32 flags = MOD_HAS_BOUND;
if (tileX == 65 && tileY == 65)
flags |= MOD_WORLDSPAWN;
fwrite(&mapID, sizeof(uint32), 1, pDirfile);
fwrite(&tileX, sizeof(uint32), 1, pDirfile);
fwrite(&tileY, sizeof(uint32), 1, pDirfile);
fwrite(&flags, sizeof(uint32), 1, pDirfile);
fwrite(&adtId, sizeof(uint16), 1, pDirfile);
fwrite(&id, sizeof(uint32), 1, pDirfile);
fwrite(&pos, sizeof(float), 3, pDirfile);
fwrite(&rot, sizeof(float), 3, pDirfile);
fwrite(&scale, sizeof(float), 1, pDirfile);
fwrite(&pos2, sizeof(float), 3, pDirfile);
fwrite(&pos3, sizeof(float), 3, pDirfile);
uint32 nlen = strlen(WmoInstName);
fwrite(&nlen, sizeof(uint32), 1, pDirfile);
fwrite(WmoInstName, sizeof(char), nlen, pDirfile);
/*fprintf(pDirfile,"MapName %s WmoInstName %s pos.x %f, pos.y %f, pos.z%f, rot.x %f, rot.y %f, rot.z %f nVertices %d\n",
MapName,
WmoInstName,
(float) x, (float) pos.y, (float) z,
(float) rot.x, (float) rot.y, (float) rot.z,
nVertices); */
// fclose(dirfile);
}

View File

@@ -0,0 +1,138 @@
/*
* Copyright (C) 2008-2015 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2011 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef WMO_H
#define WMO_H
#define TILESIZE (533.33333f)
#define CHUNKSIZE ((TILESIZE) / 16.0f)
#include <string>
#include <set>
#include "vec3d.h"
#include "mpqfile.h"
// MOPY flags
#define WMO_MATERIAL_NOCAMCOLLIDE 0x01
#define WMO_MATERIAL_DETAIL 0x02
#define WMO_MATERIAL_NO_COLLISION 0x04
#define WMO_MATERIAL_HINT 0x08
#define WMO_MATERIAL_RENDER 0x10
#define WMO_MATERIAL_COLLIDE_HIT 0x20
#define WMO_MATERIAL_WALL_SURFACE 0x40
class WMOInstance;
class WMOManager;
class MPQFile;
/* for whatever reason a certain company just can't stick to one coordinate system... */
static inline Vec3D fixCoords(const Vec3D &v){ return Vec3D(v.z, v.x, v.y); }
class WMORoot
{
private:
std::string filename;
public:
unsigned int col;
uint32 nTextures, nGroups, nP, nLights, nModels, nDoodads, nDoodadSets, RootWMOID, liquidType, flagHasSomeOutdoorGroup, FlagLod, Unk;
float bbcorn1[3];
float bbcorn2[3];
WMORoot(std::string& filename);
bool open();
bool ConvertToVMAPRootWmo(FILE* output);
};
struct WMOLiquidHeader
{
int xverts, yverts, xtiles, ytiles;
float pos_x;
float pos_y;
float pos_z;
short type;
};
#pragma pack(push, 1)
struct WMOLiquidVert
{
uint16 unk1;
uint16 unk2;
float height;
};
#pragma pack(pop)
class WMOGroup
{
private:
std::string filename;
public:
// MOGP
char* MOPY;
uint16* MOVI;
uint16* MoviEx;
float* MOVT;
uint16* MOBA;
int* MobaEx;
WMOLiquidHeader* hlq;
WMOLiquidVert* LiquEx;
char* LiquBytes;
int groupName, descGroupName;
int mogpFlags;
float bbcorn1[3];
float bbcorn2[3];
uint16 moprIdx;
uint16 moprNItems;
uint16 nBatchA;
uint16 nBatchB;
uint32 nBatchC, fogIdx, liquidType, groupWMOID, CanCutTerrain, Unused;
int mopy_size, moba_size;
int LiquEx_size;
unsigned int nVertices; // number when loaded
int nTriangles; // number when loaded
uint32 liquflags;
WMOGroup(std::string const& filename);
~WMOGroup();
bool open();
int ConvertToVMAPGroupWmo(FILE* output, WMORoot* rootWMO, bool preciseVectorData);
};
class WMOInstance
{
static std::set<int> ids;
public:
std::string MapName;
int currx;
int curry;
WMOGroup* wmo;
int doodadset;
Vec3D pos;
Vec3D pos2, pos3, rot;
uint32 indx, id, d2, d3;
WMOInstance(MPQFile&f , char const* WmoInstName, uint32 mapID, uint32 tileX, uint32 tileY, FILE* pDirfile);
static void reset();
};
#endif

View File

@@ -0,0 +1,135 @@
include(ExternalProject)
ExternalProject_Add(http
GIT_REPOSITORY https://github.com/yhirose/cpp-httplib
CONFIGURE_COMMAND ""
UPDATE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
)
ExternalProject_Add(cereal
GIT_REPOSITORY https://github.com/USCiLab/cereal
CONFIGURE_COMMAND ""
UPDATE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
)
add_library(captcha STATIC dep/libcaptcha.c)
SET (SRCS
src/main.cpp
${CMAKE_SOURCE_DIR}/src/server/game/Accounts/AccountMgr.cpp
dep/tweetnacl/tweetnacl.c
dep/smtp-client/src/smtp.c
dep/smtp-client/src/SMTPMail.cpp
)
# we use the filesystem API of C++17
set(CMAKE_CXX_STANDARD 17)
add_executable(webapi ${SRCS})
add_dependencies(webapi http captcha cereal)
if( UNIX AND NOT NOJEM AND NOT APPLE AND NOT WIN32 )
set_target_properties(webapi PROPERTIES LINK_FLAGS "-pthread")
endif()
target_compile_definitions(webapi PUBLIC _WEB_API)
ExternalProject_Get_Property(http SOURCE_DIR)
set(HTTP_SOURCE_DIR ${SOURCE_DIR})
ExternalProject_Get_Property(cereal SOURCE_DIR)
set(CEREAL_SOURCE_DIR ${SOURCE_DIR})
target_include_directories(webapi PUBLIC
${HTTP_SOURCE_DIR}
${CEREAL_SOURCE_DIR}/include
dep/tweetnacl
dep/smtp-client/src
${CMAKE_SOURCE_DIR}/src/common
${CMAKE_SOURCE_DIR}/src/common/Logging
${CMAKE_SOURCE_DIR}/src/common/Utilities
${CMAKE_SOURCE_DIR}/src/common/Threading
${CMAKE_SOURCE_DIR}/src/common/Debugging
${CMAKE_SOURCE_DIR}/src/common/Database
${CMAKE_SOURCE_DIR}/src/common/Cryptography
${CMAKE_SOURCE_DIR}/src/server/game/Accounts
${ACE_INCLUDE_DIR}
${MYSQL_INCLUDE_DIR}
${OPENSSL_INCLUDE_DIR}
)
target_link_libraries(webapi PUBLIC
shared
captcha
${ACE_LIBRARY}
${MYSQL_LIBRARY}
${OPENSSL_LIBRARIES}
)
set_target_properties(webapi PROPERTIES FOLDER "tools")
if( WIN32 )
if ( MSVC )
add_custom_command(TARGET webapi
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/webapi.conf.dist ${CMAKE_BINARY_DIR}/bin/$(ConfigurationName)/
)
add_custom_command(TARGET webapi
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/confirmation.mail.dist ${CMAKE_BINARY_DIR}/bin/$(ConfigurationName)/
)
add_custom_command(TARGET webapi
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/registration.mail.dist ${CMAKE_BINARY_DIR}/bin/$(ConfigurationName)/
)
add_custom_command(TARGET webapi
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/reset.mail.dist ${CMAKE_BINARY_DIR}/bin/$(ConfigurationName)/
)
add_custom_command(TARGET webapi
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/validation.mail.dist ${CMAKE_BINARY_DIR}/bin/$(ConfigurationName)/
)
elseif ( MINGW )
add_custom_command(TARGET webapi
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/webapi.conf.dist ${CMAKE_BINARY_DIR}/bin/
)
add_custom_command(TARGET webapi
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/confirmation.mail.dist ${CMAKE_BINARY_DIR}/bin/
)
add_custom_command(TARGET webapi
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/registration.mail.dist ${CMAKE_BINARY_DIR}/bin/
)
add_custom_command(TARGET webapi
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/reset.mail.dist ${CMAKE_BINARY_DIR}/bin/
)
add_custom_command(TARGET webapi
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/validation.mail.dist ${CMAKE_BINARY_DIR}/bin/
)
endif()
endif()
if( UNIX )
install(TARGETS webapi DESTINATION bin)
install(FILES webapi.conf.dist DESTINATION ${CONF_DIR})
install(FILES confirmation.mail.dist DESTINATION ${CONF_DIR})
install(FILES registration.mail.dist DESTINATION ${CONF_DIR})
install(FILES reset.mail.dist DESTINATION ${CONF_DIR})
install(FILES validation.mail.dist DESTINATION ${CONF_DIR})
elseif( WIN32 )
install(TARGETS webapi DESTINATION "${CMAKE_INSTALL_PREFIX}")
install(FILES webapi.conf.dist DESTINATION "${CMAKE_INSTALL_PREFIX}")
install(FILES confirmation.mail.dist DESTINATION "${CMAKE_INSTALL_PREFIX}")
install(FILES registration.mail.dist DESTINATION "${CMAKE_INSTALL_PREFIX}")
install(FILES reset.mail.dist DESTINATION "${CMAKE_INSTALL_PREFIX}")
install(FILES validation.mail.dist DESTINATION "${CMAKE_INSTALL_PREFIX}")
endif()

View File

View File

@@ -0,0 +1,18 @@
--dakjqwmnejadhasdkljkaeiasndansdahjdhjasd
Content-Type: text/plain
Please open the following link in your webbrowser to complete the upgrade for your WoW account (you will be able to login to WoW then using this email address):
<insert-url>
--dakjqwmnejadhasdkljkaeiasndansdahjdhjasd
Content-Type: text/html
<html>
<head>
<title>WoW Account Upgrade Confirmation</title>
</head>
<body>Please click the following link to complete the upgrade for your WoW account (you will be able to login to WoW then using this email address):<br>
<a href="<insert-url>"><insert-url></a>
</body></html>
--dakjqwmnejadhasdkljkaeiasndansdahjdhjasd--

View File

@@ -0,0 +1,257 @@
// Version 2012-02-20 (http://github.com/ITikhonov/captcha/tree/bbbaaa33ad3f94ce3f091badba51b44a231f12fd)
// zlib/libpng license is at the end of this file
const int gifsize;
void captcha(unsigned char im[70*200], unsigned char l[6]);
void makegif(unsigned char im[70*200], unsigned char gif[17646]);
#ifdef WIN32
#include <io.h>
#else
#include <unistd.h>
#endif
#include <stdint.h>
#include <fcntl.h>
#include <string.h>
static int8_t lt0[] = { -100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-4,11,7,5,3,1,0,0,0,1,3,7,13,-100,-2,11,3,0,0,0,0,0,0,0,0,0,0,0,0,9,-100,-1,7,0,0,0,0,0,0,3,9,11,9,3,0,0,0,0,13,-100,9,0,0,0,0,0,0,3,-5,3,0,0,0,7,-100,5,0,0,0,0,0,1,13,-5,9,0,0,0,1,-100,7,0,0,0,0,1,13,-6,13,0,0,0,0,-100,-1,9,1,0,5,13,-8,0,0,0,0,13,-100,-14,0,0,0,0,11,-100,-14,0,0,0,0,11,-100,-14,0,0,0,0,11,-100,-12,13,5,0,0,0,0,11,-100,-8,13,9,5,1,0,0,0,0,0,0,11,-100,-4,13,7,3,1,0,0,0,0,1,1,0,0,0,0,11,-100,-2,13,5,0,0,0,0,0,5,9,13,-2,0,0,0,0,11,-100,-1,13,1,0,0,0,0,7,-6,0,0,0,0,11,-100,13,1,0,0,0,0,13,-7,0,0,0,0,11,-100,5,0,0,0,0,5,-8,0,0,0,0,11,-100,0,0,0,0,0,11,-8,0,0,0,0,11,-100,0,0,0,0,0,13,-7,13,0,0,0,0,11,-100,1,0,0,0,0,-7,9,0,0,0,0,0,9,-3,9,-100,5,0,0,0,0,3,13,-3,11,3,0,0,0,0,0,0,0,9,13,3,5,-100,13,0,0,0,0,0,0,1,1,0,0,0,1,11,9,0,0,0,0,0,0,1,13,-100,-1,11,1,0,0,0,0,0,0,0,0,5,-3,9,0,0,0,0,0,11,-100,-2,13,7,3,0,0,0,3,7,13,-5,9,0,1,3,9,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-101 };
static int8_t lt1[] = { -100,-100,-4,13,5,0,3,-100,-3,11,1,0,0,0,7,-100,-2,7,0,0,0,0,0,3,-100,13,3,0,0,0,0,0,0,5,-100,1,0,0,0,0,0,0,0,9,-100,1,0,0,0,0,0,0,0,13,-100,13,3,0,0,0,0,0,1,-100,-2,5,0,0,0,0,5,-100,-3,0,0,0,0,9,-100,-3,0,0,0,0,11,-100,-3,0,0,0,0,11,-100,-3,0,0,0,0,9,-100,-3,0,0,0,0,11,-100,-3,0,0,0,0,11,-100,-3,0,0,0,0,11,-100,-3,0,0,0,0,3,13,9,5,3,1,0,0,1,3,5,9,-100,-3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,13,-100,-3,0,0,0,0,0,5,13,-2,13,11,9,5,0,0,0,0,1,13,-100,-3,0,0,0,0,1,-8,13,1,0,0,0,5,-100,-3,3,0,0,0,5,-9,13,0,0,0,0,11,-100,-3,0,0,0,0,9,-10,7,0,0,0,5,-100,-3,1,0,0,0,11,-10,13,0,0,0,0,-100,-3,3,0,0,0,11,-11,3,0,0,0,11,-100,-3,1,0,0,0,11,-11,7,0,0,0,7,-100,-3,0,0,0,0,11,-11,9,0,0,0,3,-100,-3,0,0,0,0,11,-11,11,0,0,0,1,-100,-3,0,0,0,0,11,-11,11,0,0,0,1,-100,-3,0,0,0,0,11,-11,11,0,0,0,0,-100,-3,0,0,0,0,11,-11,9,0,0,0,0,-100,-3,0,0,0,0,11,-11,7,0,0,0,3,-100,-3,0,0,0,0,11,-11,3,0,0,0,7,-100,-3,0,0,0,0,11,-11,0,0,0,0,11,-100,-3,0,0,0,0,11,-10,9,0,0,0,3,-100,-3,0,0,0,0,9,-10,3,0,0,0,11,-100,-3,0,0,0,0,3,-9,11,0,0,0,5,-100,-2,13,0,0,0,0,0,9,-7,11,1,0,0,3,-100,-2,7,0,0,0,0,0,0,7,13,-2,13,9,3,0,0,0,3,13,-100,-2,13,0,0,5,13,11,1,0,0,0,0,0,0,0,0,0,7,-100,-3,9,11,-4,7,3,1,0,0,1,5,9,13,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-101 };
static int8_t lt2[] = { -100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-6,13,7,3,1,0,0,1,3,7,13,-100,-5,9,0,0,0,0,0,0,0,0,0,0,5,13,-100,-3,13,3,0,0,0,5,13,13,7,0,0,0,0,0,1,13,-100,-2,13,1,0,0,0,9,-4,7,0,0,0,0,0,1,-100,-1,13,1,0,0,0,9,-6,5,0,0,0,0,0,13,-100,-1,5,0,0,0,3,-8,1,0,0,0,3,-100,13,0,0,0,0,11,-8,13,3,0,3,-100,7,0,0,0,1,-100,5,0,0,0,5,-100,3,0,0,0,9,-100,1,0,0,0,11,-100,0,0,0,0,11,-100,0,0,0,0,11,-100,0,0,0,0,11,-100,0,0,0,0,9,-100,1,0,0,0,5,-100,5,0,0,0,0,13,-100,11,0,0,0,0,7,-100,-1,3,0,0,0,0,13,-100,-1,11,0,0,0,0,3,-12,9,-100,-2,7,0,0,0,0,3,13,-8,9,1,3,-100,-3,5,0,0,0,0,1,9,-5,9,3,0,0,11,-100,-4,5,0,0,0,0,0,0,1,1,1,0,0,0,0,11,-100,-5,9,1,0,0,0,0,0,0,0,0,0,3,13,-100,-7,11,7,3,1,0,1,3,7,11,-100,-100,-100,-100,-100,-100,-100,-100,-100,-101 };
static int8_t lt3[] = { -100,-100,-100,-100,-18,11,3,0,-100,-16,13,3,0,0,0,-100,-14,9,3,0,0,0,0,0,-100,-13,3,0,0,0,0,0,0,0,-100,-13,0,0,0,0,0,0,0,0,-100,-13,9,1,0,0,0,0,0,0,-100,-15,13,5,0,0,0,0,-100,-17,1,0,0,0,-100,-17,3,0,0,0,-100,-17,1,0,0,0,-100,-17,0,0,0,0,-100,-16,13,0,0,0,0,-100,-16,13,0,0,0,0,-100,-6,11,5,3,1,0,0,1,5,9,13,13,0,0,0,0,-100,-4,13,3,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,-100,-3,13,1,0,0,0,0,5,11,-1,13,11,3,0,0,0,0,0,0,-100,-2,13,1,0,0,0,0,7,-6,11,0,0,0,0,0,-100,-2,3,0,0,0,0,9,-8,11,0,0,0,0,-100,-1,9,0,0,0,0,7,-9,11,0,0,0,0,-100,-1,1,0,0,0,0,13,-9,11,0,0,0,0,-100,11,0,0,0,0,3,-10,11,0,0,0,0,-100,5,0,0,0,0,13,-10,11,0,0,0,0,-100,3,0,0,0,3,-11,11,0,0,0,0,-100,0,0,0,0,7,-11,11,0,0,0,0,-100,0,0,0,0,11,-11,11,0,0,0,0,-100,0,0,0,0,11,-11,11,0,0,0,0,-100,0,0,0,0,11,-11,11,0,0,0,0,-100,1,0,0,0,9,-11,11,0,0,0,0,-100,3,0,0,0,7,-11,11,0,0,0,0,-100,7,0,0,0,3,-11,11,0,0,0,0,-100,13,0,0,0,0,13,-10,13,0,0,0,0,-100,-1,3,0,0,0,5,-11,0,0,0,0,-100,-1,13,0,0,0,0,11,-10,0,0,0,0,-100,-2,7,0,0,0,1,13,-8,13,0,0,0,0,13,-100,-3,5,0,0,0,1,11,-7,5,0,0,0,0,9,-100,-4,5,0,0,0,0,3,9,13,-1,13,11,1,0,0,0,0,0,0,0,5,-100,-5,9,1,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,1,13,-100,-7,9,3,1,0,0,3,7,13,-1,11,1,0,1,5,7,11,-100,-18,13,-100,-100,-100,-100,-100,-100,-100,-100,-101 };
static int8_t lt4[] = { -100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-7,13,5,1,1,0,1,3,9,13,-100,-6,5,0,0,0,0,0,0,0,0,0,9,-100,-4,11,1,0,0,3,11,-1,13,7,1,0,0,0,9,-100,-3,9,0,0,0,1,13,-5,3,0,0,1,-100,-2,9,0,0,0,0,13,-6,11,0,0,0,9,-100,-1,13,0,0,0,0,9,-8,0,0,0,1,-100,-1,5,0,0,0,0,13,-8,3,0,0,0,11,-100,-1,0,0,0,0,0,-8,13,1,0,0,0,5,-100,9,0,0,0,0,0,3,11,-4,13,11,1,0,0,0,0,1,-100,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-100,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,-100,1,0,0,0,1,13,-100,0,0,0,0,11,-100,0,0,0,0,11,-100,1,0,0,0,9,-100,3,0,0,0,7,-100,7,0,0,0,5,-100,13,0,0,0,0,11,-100,-1,5,0,0,0,1,13,-100,-1,13,1,0,0,0,1,13,-10,13,11,-100,-2,11,0,0,0,0,1,13,-8,13,1,1,-100,-3,11,0,0,0,0,0,7,13,-4,11,7,0,0,9,-100,-4,11,1,0,0,0,0,0,1,1,1,0,0,0,0,7,-100,-5,13,5,0,0,0,0,0,0,0,0,0,1,9,-100,-7,13,7,3,0,0,0,1,5,9,-100,-100,-100,-100,-100,-100,-100,-100,-100,-101 };
static int8_t lt5[] = { -100,-100,-100,-100,-9,13,9,3,1,0,1,5,13,-100,-8,7,0,0,0,0,0,0,0,3,-100,-7,3,0,0,0,0,0,0,0,0,1,-100,-6,5,0,0,0,0,0,0,0,0,0,3,-100,-5,13,0,0,3,13,9,1,0,0,0,0,11,-100,-5,9,0,0,13,-2,13,5,0,1,9,-100,-5,5,0,0,-100,-5,1,0,1,-100,-5,1,0,0,-100,-5,0,0,0,-100,-5,0,0,0,13,-100,-5,0,0,0,9,-100,-5,0,0,0,7,-100,-5,0,0,0,5,-100,-3,13,7,0,0,0,0,9,-1,13,11,13,-100,3,0,0,0,0,0,0,0,0,0,0,0,0,0,9,-100,3,0,0,0,0,0,0,0,0,0,0,0,0,0,9,-100,-1,11,13,-1,7,0,0,0,0,5,-1,13,11,13,-100,-5,0,0,0,0,11,-100,-5,0,0,0,0,11,-100,-5,0,0,0,0,11,-100,-5,0,0,0,0,11,-100,-5,0,0,0,0,11,-100,-5,0,0,0,0,11,-100,-5,0,0,0,0,11,-100,-5,0,0,0,0,11,-100,-5,0,0,0,0,11,-100,-5,0,0,0,0,11,-100,-5,0,0,0,0,11,-100,-5,0,0,0,0,11,-100,-5,0,0,0,0,11,-100,-5,0,0,0,0,11,-100,-5,0,0,0,0,11,-100,-5,0,0,0,0,7,-100,-3,13,5,0,0,0,0,0,7,13,-100,-1,5,0,0,0,0,0,0,0,0,0,0,0,1,11,-100,-1,7,1,0,0,0,0,0,0,0,0,1,3,7,13,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-101 };
static int8_t lt6[] = { -100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-7,11,7,3,1,0,0,1,3,7,13,-4,13,7,5,7,11,-100,-5,11,3,0,0,0,0,0,0,0,0,0,0,5,13,13,5,0,0,0,0,0,-100,-4,9,0,0,0,5,13,-1,13,9,3,0,0,0,0,0,0,0,0,0,0,0,1,-100,-3,11,0,0,0,5,-6,5,0,0,0,0,0,11,13,9,3,0,9,-100,-2,13,0,0,0,0,13,-7,1,0,0,0,0,13,-100,-2,1,0,0,0,7,-8,7,0,0,0,0,7,-100,-2,0,0,0,0,9,-8,11,0,0,0,0,3,-100,-2,0,0,0,0,11,-9,0,0,0,0,1,-100,-2,0,0,0,0,11,-9,0,0,0,0,0,-100,-2,0,0,0,0,9,-8,13,0,0,0,0,1,-100,-2,3,0,0,0,5,-8,9,0,0,0,0,7,-100,-2,13,1,0,0,0,13,-7,5,0,0,0,0,13,-100,-3,11,0,0,0,3,13,-5,7,0,0,0,0,11,-100,-4,7,0,0,0,1,9,13,-1,13,7,0,0,0,1,11,-100,-4,13,0,0,0,0,0,0,0,0,0,0,0,5,13,-100,-4,13,0,0,0,0,0,0,1,3,5,9,-100,-2,13,5,0,11,-100,-1,13,1,0,0,-100,-1,3,0,0,0,1,7,13,-100,-1,0,0,0,0,0,0,0,1,3,7,9,11,13,-100,-1,5,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,5,11,-100,-2,11,7,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,11,-100,-4,13,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,-100,-3,9,1,0,3,9,13,13,11,7,3,0,0,0,0,0,0,0,0,0,13,-100,-1,7,1,0,0,9,-8,11,7,3,0,0,0,0,0,5,-100,9,0,0,0,3,-13,11,1,0,0,1,-100,1,0,0,0,9,-15,0,0,0,-100,0,0,0,0,9,-14,13,0,0,1,-100,3,0,0,0,1,-14,7,0,0,5,-100,11,0,0,0,0,5,-12,11,0,0,0,13,-100,-1,11,1,0,0,0,1,7,11,13,-1,13,13,11,9,5,3,1,0,0,3,13,-100,-3,9,3,0,0,0,0,0,0,0,0,0,0,0,0,0,1,9,-100,-6,9,7,3,1,1,0,0,1,1,3,7,11,-100,-101 };
static int8_t lt7[] = { -100,-100,-100,-100,-4,13,7,1,9,-100,-2,13,7,0,0,0,3,-100,-1,7,0,0,0,0,0,5,-100,1,0,0,0,0,0,0,7,-100,3,0,0,0,0,0,0,7,-100,13,7,0,0,0,0,0,9,-100,-2,5,0,0,0,0,9,-100,-2,11,0,0,0,0,9,-100,-3,0,0,0,0,9,-100,-3,0,0,0,0,11,-100,-3,0,0,0,0,11,-100,-3,0,0,0,0,11,-100,-3,0,0,0,0,11,-100,-3,0,0,0,0,11,-100,-3,0,0,0,0,11,-5,11,5,1,0,1,7,-100,-3,0,0,0,0,11,-3,13,3,0,0,0,0,0,0,3,-100,-3,0,0,0,0,11,-2,7,0,0,0,0,0,0,0,0,0,9,-100,-3,0,0,0,0,11,11,3,0,5,11,-1,13,9,1,0,0,0,3,-100,-3,0,0,0,0,3,0,1,11,-6,1,0,0,0,13,-100,-3,0,0,0,0,0,5,-8,11,0,0,0,11,-100,-3,0,0,0,0,11,-10,0,0,0,7,-100,-3,0,0,0,0,13,-10,0,0,0,7,-100,-3,0,0,0,0,11,-10,0,0,0,7,-100,-3,0,0,0,0,11,-10,0,0,0,7,-100,-3,0,0,0,0,13,-10,0,0,0,9,-100,-3,0,0,0,0,13,-10,0,0,0,9,-100,-3,0,0,0,0,-11,0,0,0,11,-100,-3,0,0,0,1,-11,0,0,0,13,-100,-3,0,0,0,1,-11,0,0,0,13,-100,-3,0,0,0,3,-11,0,0,0,-100,-3,0,0,0,3,-11,0,0,0,-100,-3,0,0,0,3,-11,0,0,0,-100,-3,0,0,0,3,-10,13,0,0,0,13,-100,-3,0,0,0,1,-10,13,0,0,0,11,-100,-2,9,0,0,0,0,-10,11,0,0,0,5,-100,-1,7,0,0,0,0,0,5,13,-7,13,3,0,0,0,0,7,-100,5,0,0,0,0,0,0,0,0,3,-5,1,0,0,0,0,0,0,1,3,11,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-101 };
static int8_t lt8[] = { -100,-100,-100,-100,-3,5,1,0,3,11,-100,-2,7,0,0,0,0,0,11,-100,-2,1,0,0,0,0,0,5,-100,-2,0,0,0,0,0,0,5,-100,-2,5,0,0,0,0,0,11,-100,-3,7,0,0,3,9,-100,-4,13,-100,-100,-100,-100,-100,-100,-100,-4,11,3,0,9,-100,-2,9,3,0,0,0,9,-100,11,1,0,0,0,0,0,7,-100,1,0,0,0,0,0,0,7,-100,1,0,0,0,0,0,0,9,-100,-1,11,0,0,0,0,0,9,-100,-2,7,0,0,0,0,11,-100,-3,0,0,0,0,13,-100,-3,1,0,0,0,-100,-3,1,0,0,0,13,-100,-3,1,0,0,0,13,-100,-3,0,0,0,0,11,-100,-3,0,0,0,0,11,-100,-3,0,0,0,0,11,-100,-3,0,0,0,0,11,-100,-3,0,0,0,0,11,-100,-3,0,0,0,0,11,-100,-3,0,0,0,0,11,-100,-3,0,0,0,0,11,-100,-2,13,0,0,0,0,7,-100,-2,13,0,0,0,0,1,-100,-2,7,0,0,0,0,0,9,-100,7,0,0,0,0,0,0,0,0,3,-100,9,5,1,1,0,0,1,1,3,5,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-101 };
static int8_t lt9[] = { -100,-100,-100,-100,-6,5,0,1,5,13,-100,-5,5,0,0,0,0,1,-100,-5,1,0,0,0,0,0,13,-100,-5,0,0,0,0,0,0,-100,-5,5,0,0,0,0,3,-100,-6,7,1,0,5,13,-100,-100,-100,-100,-100,-100,-100,-100,-6,13,7,3,0,13,-100,-5,7,0,0,0,0,11,-100,-3,7,1,0,0,0,0,0,11,-100,-2,13,0,0,0,0,0,0,0,11,-100,-3,11,3,0,0,0,0,0,11,-100,-5,9,0,0,0,0,11,-100,-6,1,0,0,0,11,-100,-6,3,0,0,0,11,-100,-6,5,0,0,0,11,-100,-6,5,0,0,0,11,-100,-6,5,0,0,0,11,-100,-6,5,0,0,0,11,-100,-6,3,0,0,0,11,-100,-6,3,0,0,0,11,-100,-6,1,0,0,0,11,-100,-6,1,0,0,0,13,-100,-6,1,0,0,0,13,-100,-6,1,0,0,0,13,-100,-6,1,0,0,0,13,-100,-6,1,0,0,0,13,-100,-6,1,0,0,0,-100,-6,1,0,0,0,-100,-6,1,0,0,1,-100,-6,1,0,0,3,-100,-6,0,0,0,5,-100,-6,0,0,0,7,-100,-6,0,0,0,11,-100,11,0,0,0,5,5,0,0,5,-100,3,0,0,0,0,0,0,3,-100,0,0,0,0,0,0,0,13,-100,1,0,0,0,0,0,11,-100,13,3,0,0,3,11,-100,-100,-101 };
static int8_t lt10[] = { -100,-100,-100,-100,-6,9,1,13,-100,-3,13,5,0,0,0,11,-100,-1,13,5,0,0,0,0,0,11,-100,13,1,0,0,0,0,0,0,11,-100,3,0,0,0,0,0,0,0,11,-100,11,3,0,0,0,0,0,0,11,-100,-2,13,0,0,0,0,0,11,-100,-3,9,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-7,3,0,0,0,0,0,0,0,0,0,3,-100,-4,0,0,0,0,11,-7,5,0,0,0,0,0,0,0,1,7,13,-100,-4,0,0,0,0,11,-8,9,0,0,0,1,9,-100,-4,0,0,0,0,11,-7,13,1,0,0,7,-100,-4,0,0,0,0,11,-7,5,0,3,13,-100,-4,0,0,0,0,11,-6,5,0,5,-100,-4,0,0,0,0,11,-5,5,1,11,-100,-4,0,0,0,0,11,-3,11,3,1,-100,-4,0,0,0,0,11,-1,11,3,0,0,1,-100,-4,0,0,0,0,11,9,0,0,0,0,0,11,-100,-4,0,0,0,0,0,0,1,0,0,0,0,3,-100,-4,0,0,0,0,0,9,-1,11,1,0,0,0,9,-100,-4,0,0,0,0,5,-4,3,0,0,0,11,-100,-4,0,0,0,0,11,-4,13,1,0,0,0,13,-100,-4,0,0,0,0,11,-5,11,0,0,0,1,13,-100,-4,0,0,0,0,11,-6,3,0,0,0,3,-100,-4,0,0,0,0,11,-6,11,0,0,0,0,7,-100,-4,0,0,0,0,11,-7,3,0,0,0,0,7,-100,-3,13,0,0,0,0,11,-7,13,0,0,0,0,0,7,-100,-2,13,3,0,0,0,0,7,-7,9,0,0,0,0,0,0,3,11,-100,-1,1,0,0,0,0,0,0,0,0,1,3,-4,0,0,0,0,0,0,0,0,0,0,3,-100,-1,7,1,0,0,0,0,0,0,0,0,7,-4,3,0,0,0,0,0,0,1,1,5,9,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-101 };
static int8_t lt11[] = { -100,-100,-100,-6,11,7,11,-100,-4,11,3,0,0,5,-100,-3,5,0,0,0,0,5,-100,-1,11,1,0,0,0,0,0,7,-100,7,0,0,0,0,0,0,0,7,-100,0,0,0,0,0,0,0,0,9,-100,7,0,0,0,0,0,0,0,9,-100,-2,9,1,0,0,0,0,9,-100,-3,11,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,7,-100,-3,5,0,0,0,0,0,13,-100,-1,9,1,0,0,0,0,0,0,0,1,9,-100,-1,5,1,0,0,0,0,0,0,0,1,11,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-101 };
static int8_t lt12[] = { -100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-5,11,5,0,-21,7,1,0,3,9,-100,-4,7,0,0,0,13,-4,11,5,1,1,0,1,7,-7,11,3,0,0,0,0,0,5,-100,-2,11,1,0,0,0,0,11,-2,9,1,0,0,0,0,0,0,0,9,-4,13,5,0,0,0,0,0,0,0,0,7,-100,13,3,0,0,0,0,0,0,7,13,3,0,0,0,1,0,0,0,0,0,0,7,-1,13,7,0,0,0,0,0,0,0,0,0,0,0,11,-100,3,0,0,0,0,0,0,0,1,0,0,5,11,-3,11,0,0,0,0,0,0,0,3,9,13,13,-3,7,0,0,0,0,5,-100,13,3,0,0,0,0,0,0,0,7,13,-6,3,0,0,0,0,0,9,-8,5,0,0,0,1,-100,-2,11,0,0,0,0,0,3,-8,9,0,0,0,0,7,-9,11,0,0,0,0,-100,-3,3,0,0,0,0,7,-8,13,0,0,0,0,-10,11,0,0,0,0,-100,-3,7,0,0,0,0,11,-9,0,0,0,0,-10,11,0,0,0,1,-100,-3,11,0,0,0,0,11,-9,0,0,0,0,-10,11,0,0,0,3,-100,-3,13,0,0,0,0,11,-8,13,0,0,0,0,-10,11,0,0,0,5,-100,-3,13,0,0,0,0,11,-8,11,0,0,0,0,-10,11,0,0,0,5,-100,-4,0,0,0,0,13,-8,9,0,0,0,0,-10,11,0,0,0,5,-100,-4,0,0,0,0,13,-8,11,0,0,0,0,-10,11,0,0,0,3,-100,-4,0,0,0,0,13,-8,11,0,0,0,0,-10,11,0,0,0,0,-100,-3,13,0,0,0,1,-9,13,0,0,0,0,-10,11,0,0,0,0,-100,-3,11,0,0,0,13,-10,0,0,0,0,-10,11,0,0,0,0,-100,-4,0,0,0,11,-10,0,0,0,0,-10,11,0,0,0,0,-100,-3,13,0,0,0,3,-9,13,0,0,0,0,13,-9,9,0,0,0,0,-100,-3,7,0,0,0,0,13,-8,11,0,0,0,0,11,-9,7,0,0,0,0,13,-100,-3,3,0,0,0,0,9,-8,5,0,0,0,0,5,-9,5,0,0,0,0,7,-100,-1,13,3,0,0,0,0,0,1,11,-6,9,0,0,0,0,0,0,3,-7,11,1,0,0,0,0,1,13,-100,11,0,0,0,0,0,0,0,0,0,3,-4,3,0,0,0,0,0,0,0,0,5,-5,1,0,0,0,0,0,0,0,0,9,-100,13,1,0,0,0,0,0,0,0,1,9,-4,1,0,0,0,0,0,0,0,1,5,-5,1,0,0,0,0,0,0,0,0,7,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-101 };
static int8_t lt13[] = { -100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-3,13,7,3,0,13,-5,13,7,1,0,0,3,7,-100,-2,5,0,0,0,0,-4,13,3,0,0,0,0,0,0,0,7,-100,7,1,0,0,0,0,0,-3,7,0,0,0,0,0,0,0,0,0,0,13,-100,1,0,0,0,0,0,0,13,9,1,0,5,11,13,-1,11,3,0,0,0,0,9,-100,13,3,0,0,0,0,0,1,1,7,-7,3,0,0,0,3,-100,-2,1,0,0,0,0,7,-9,13,0,0,0,1,-100,-2,7,0,0,0,0,-11,1,0,0,0,-100,-2,9,0,0,0,0,-11,1,0,0,0,13,-100,-2,11,0,0,0,0,-11,3,0,0,0,13,-100,-2,11,0,0,0,0,-11,5,0,0,0,11,-100,-2,11,0,0,0,0,-11,3,0,0,0,11,-100,-2,11,0,0,0,0,-11,1,0,0,0,11,-100,-2,11,0,0,0,0,-11,0,0,0,0,11,-100,-2,11,0,0,0,0,-11,0,0,0,0,11,-100,-2,11,0,0,0,0,-11,1,0,0,0,11,-100,-2,11,0,0,0,0,-11,3,0,0,0,11,-100,-2,11,0,0,0,0,-11,3,0,0,0,11,-100,-2,11,0,0,0,0,13,-10,5,0,0,0,11,-100,-2,11,0,0,0,0,13,-10,5,0,0,0,11,-100,-2,11,0,0,0,0,9,-10,5,0,0,0,9,-100,-2,7,0,0,0,0,5,-10,3,0,0,0,7,-100,-1,13,1,0,0,0,0,1,11,-7,11,5,0,0,0,0,0,3,9,-100,-1,1,0,0,0,0,0,0,0,0,3,-4,3,0,0,0,0,0,0,0,0,0,3,-100,-1,0,0,0,0,0,0,0,0,0,3,-4,5,1,0,0,0,0,0,0,0,0,1,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-101 };
static int8_t lt14[] = { -100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-7,13,7,3,1,0,0,1,5,9,-100,-6,7,0,0,0,0,0,0,0,0,0,1,7,-100,-4,11,1,0,0,1,9,13,-1,13,11,5,0,0,0,3,13,-100,-3,11,0,0,0,3,13,-6,13,1,0,0,0,13,-100,-2,11,0,0,0,1,13,-8,13,0,0,0,5,-100,-2,0,0,0,0,9,-10,5,0,0,0,11,-100,-1,7,0,0,0,1,-11,13,0,0,0,1,-100,-1,1,0,0,0,5,-12,1,0,0,0,9,-100,11,0,0,0,0,11,-12,5,0,0,0,3,-100,7,0,0,0,0,13,-12,9,0,0,0,0,-100,3,0,0,0,0,13,-12,11,0,0,0,0,-100,1,0,0,0,0,-13,11,0,0,0,1,-100,0,0,0,0,0,-13,11,0,0,0,1,-100,0,0,0,0,0,13,-12,11,0,0,0,0,-100,1,0,0,0,0,13,-12,9,0,0,0,1,-100,5,0,0,0,0,11,-12,5,0,0,0,3,-100,9,0,0,0,0,9,-12,3,0,0,0,7,-100,-1,1,0,0,0,5,-12,0,0,0,0,11,-100,-1,9,0,0,0,3,-11,13,0,0,0,3,-100,-2,3,0,0,0,13,-10,7,0,0,0,11,-100,-2,13,1,0,0,3,-9,13,0,0,0,7,-100,-3,13,1,0,0,3,13,-6,13,1,0,0,5,-100,-4,13,1,0,0,1,7,13,-3,9,0,0,0,7,-100,-6,7,0,0,0,0,0,0,0,0,0,3,11,-100,-7,13,7,3,0,0,0,0,3,11,-100,-100,-100,-100,-100,-100,-100,-100,-100,-101 };
static int8_t lt15[] = { -100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-6,11,7,-100,-4,11,3,0,0,7,11,5,3,0,0,0,1,5,9,-100,-2,11,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,-100,13,5,0,0,0,0,0,0,0,1,7,11,13,-1,13,3,0,0,0,5,-100,1,0,0,0,0,0,0,0,3,-7,7,0,0,0,7,-100,1,0,0,0,0,0,0,0,11,-8,7,0,0,0,13,-100,-1,11,5,0,0,0,0,0,11,-9,1,0,0,3,-100,-3,7,0,0,0,0,11,-9,5,0,0,0,11,-100,-3,9,0,0,0,0,11,-9,9,0,0,0,5,-100,-3,11,0,0,0,0,11,-9,11,0,0,0,0,13,-100,-3,11,0,0,0,0,11,-9,13,0,0,0,0,11,-100,-3,13,0,0,0,0,11,-10,0,0,0,0,11,-100,-3,13,0,0,0,0,11,-10,0,0,0,0,11,-100,-3,13,0,0,0,0,11,-10,0,0,0,0,11,-100,-4,0,0,0,0,11,-10,0,0,0,0,13,-100,-4,0,0,0,0,11,-10,0,0,0,0,13,-100,-4,0,0,0,0,13,-10,0,0,0,0,-100,-4,0,0,0,9,-11,0,0,0,3,-100,-4,0,0,0,3,-11,0,0,0,9,-100,-4,0,0,0,0,13,-10,0,0,0,13,-100,-4,0,0,0,0,11,-9,5,0,0,0,-100,-4,0,0,0,0,11,-8,7,0,0,0,7,-100,-4,0,0,0,0,5,-7,9,0,0,0,3,-100,-4,0,0,0,0,0,3,11,13,-3,9,0,0,0,1,-100,-4,0,0,0,0,5,7,0,0,0,1,1,0,0,0,1,13,-100,-4,0,0,0,0,11,-2,9,5,1,0,0,3,7,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,7,-100,-4,0,0,0,0,3,-100,-3,7,0,0,0,0,0,9,-100,-1,5,0,0,0,0,0,0,0,0,0,0,5,-100,-1,3,1,0,0,0,0,0,0,0,0,0,5,-100,-101 };
static int8_t lt16[] = { -100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-19,7,11,-100,-6,11,5,1,0,0,1,5,11,-4,5,0,3,-100,-4,13,3,0,0,0,0,0,0,0,0,1,11,13,5,0,0,1,-100,-3,13,1,0,0,1,5,11,-3,11,3,0,0,0,0,0,3,-100,-2,13,1,0,0,3,-8,3,0,0,0,0,5,-100,-1,13,1,0,0,0,13,-8,7,0,0,0,0,5,-100,-1,3,0,0,0,5,-9,11,0,0,0,0,7,-100,9,0,0,0,0,11,-9,13,0,0,0,0,9,-100,3,0,0,0,0,-10,13,0,0,0,0,9,-100,1,0,0,0,1,-11,0,0,0,0,9,-100,0,0,0,0,3,-11,0,0,0,0,11,-100,0,0,0,0,5,-11,0,0,0,0,11,-100,0,0,0,0,9,-11,0,0,0,0,11,-100,0,0,0,0,11,-11,0,0,0,0,11,-100,0,0,0,0,11,-11,0,0,0,0,11,-100,1,0,0,0,11,-11,0,0,0,0,11,-100,3,0,0,0,9,-11,0,0,0,0,11,-100,7,0,0,0,5,-11,0,0,0,0,11,-100,11,0,0,0,0,-11,0,0,0,0,11,-100,-1,1,0,0,0,7,-9,11,0,0,0,0,11,-100,-1,9,0,0,0,0,13,-8,9,0,0,0,0,11,-100,-2,3,0,0,0,1,13,-7,5,0,0,0,0,11,-100,-2,13,3,0,0,0,1,9,13,-3,13,7,0,0,0,0,0,11,-100,-4,9,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,11,-100,-6,11,7,3,1,0,0,5,9,-1,13,0,0,0,0,11,-100,-16,0,0,0,0,13,-100,-16,0,0,0,0,13,-100,-16,0,0,0,0,13,-100,-16,0,0,0,0,13,-100,-15,13,0,0,0,0,13,-100,-15,9,0,0,0,0,11,-100,-15,1,0,0,0,0,5,-100,-12,7,5,1,0,0,0,0,0,0,1,3,9,-100,-11,13,1,0,0,0,0,0,0,0,0,0,0,7,-100,-101 };
static int8_t lt17[] = { -100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-3,13,5,0,3,-5,9,3,1,0,0,3,-100,-1,11,3,0,0,0,0,-3,7,0,0,0,0,0,0,0,5,-100,9,0,0,0,0,0,0,-2,3,0,0,0,0,0,0,0,0,1,-100,0,0,0,0,0,0,0,11,3,0,0,0,0,0,0,0,0,0,1,-100,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,-100,-1,7,0,0,0,0,0,0,7,13,-2,11,7,3,1,3,11,-100,-2,3,0,0,0,0,3,-100,-2,7,0,0,0,0,9,-100,-2,11,0,0,0,0,13,-100,-2,13,0,0,0,0,-100,-3,0,0,0,0,-100,-3,0,0,0,0,13,-100,-3,0,0,0,0,13,-100,-3,0,0,0,0,13,-100,-3,0,0,0,0,11,-100,-3,0,0,0,0,11,-100,-3,0,0,0,0,11,-100,-3,0,0,0,0,11,-100,-3,0,0,0,0,11,-100,-3,0,0,0,0,11,-100,-3,0,0,0,0,9,-100,-1,13,3,0,0,0,0,1,13,-100,3,0,0,0,0,0,0,0,0,0,0,13,-100,5,1,0,0,0,0,0,0,0,0,3,13,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-101 };
static int8_t lt18[] = { -100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-3,13,7,1,0,1,3,9,11,9,9,13,-100,-2,13,1,0,0,0,0,0,0,0,0,0,5,-100,-2,1,0,5,13,-1,13,11,3,0,0,0,1,-100,-1,9,0,1,-6,9,0,0,0,13,-100,-1,3,0,9,-7,11,1,0,9,-100,-1,0,0,-9,13,1,5,-100,-1,0,0,11,-9,13,11,-100,13,0,0,1,13,-100,13,0,0,0,1,9,-100,-1,0,0,0,0,0,0,5,9,-100,-1,5,0,0,0,0,0,0,0,1,7,13,-100,-1,13,0,0,0,0,0,0,0,0,0,0,9,-100,-2,13,1,0,0,0,0,0,0,0,0,0,7,-100,-4,11,5,0,0,0,0,0,0,0,0,7,-100,-7,9,5,0,0,0,0,0,0,13,-100,-9,13,7,0,0,0,0,7,-100,-11,13,3,0,0,3,-100,-13,0,0,0,-100,7,5,-11,1,0,0,-100,1,0,5,-10,1,0,3,-100,0,0,0,3,-9,0,0,9,-100,1,0,0,0,3,13,-6,5,0,3,-100,7,0,0,0,0,1,7,11,13,13,9,3,0,1,13,-100,13,0,0,0,0,0,0,0,0,0,0,0,3,13,-100,-1,5,3,9,7,3,1,0,0,1,5,11,-100,-100,-100,-100,-100,-100,-100,-100,-100,-101 };
static int8_t lt19[] = { -100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-6,5,0,5,-100,-5,13,0,0,0,7,-100,-5,7,0,0,0,9,-100,-5,3,0,0,0,13,-100,-4,11,0,0,0,0,-100,-4,3,0,0,0,0,-100,-3,5,0,0,0,0,1,-100,-2,3,0,0,0,0,0,7,-100,13,1,0,0,0,0,0,0,1,11,-100,3,0,0,0,0,0,0,0,0,0,0,0,0,0,5,13,-100,1,0,0,0,0,0,0,0,0,0,0,0,0,0,5,-100,-3,9,0,0,0,0,7,13,-100,-4,0,0,0,0,11,-100,-4,1,0,0,0,11,-100,-4,1,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,0,0,0,0,11,-100,-4,1,0,0,0,11,-100,-4,3,0,0,0,11,-100,-4,5,0,0,0,11,-100,-4,3,0,0,0,11,-100,-4,3,0,0,0,11,-100,-4,1,0,0,0,9,-100,-4,0,0,0,0,5,-100,-4,0,0,0,0,1,-100,-4,1,0,0,0,0,11,-100,-4,3,0,0,0,0,1,13,-1,9,5,1,3,-100,-4,9,0,0,0,0,0,0,0,0,0,0,5,-100,-5,5,0,0,0,0,0,0,0,0,5,-100,-6,9,3,1,0,0,1,5,11,-100,-100,-100,-100,-100,-100,-100,-100,-100,-101 };
static int8_t lt20[] = { -100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-4,13,9,1,0,13,-11,11,5,1,5,-100,-2,11,3,0,0,0,0,11,-8,11,5,0,0,0,0,1,-100,13,3,0,0,0,0,0,0,11,-6,7,1,0,0,0,0,0,0,7,-100,5,0,0,0,0,0,0,0,11,-5,5,0,0,0,0,0,0,0,0,11,-100,11,1,0,0,0,0,0,0,11,-5,9,0,0,0,0,0,0,0,0,11,-100,-2,11,1,0,0,0,0,11,-6,13,7,3,0,0,0,0,0,11,-100,-3,9,0,0,0,0,11,-9,9,0,0,0,0,11,-100,-3,11,0,0,0,0,11,-10,0,0,0,0,11,-100,-3,13,0,0,0,0,11,-10,0,0,0,0,11,-100,-4,0,0,0,0,11,-10,0,0,0,0,11,-100,-4,0,0,0,0,11,-10,0,0,0,0,11,-100,-4,0,0,0,0,11,-10,0,0,0,0,11,-100,-4,0,0,0,0,11,-10,0,0,0,0,11,-100,-4,0,0,0,0,11,-10,0,0,0,0,11,-100,-4,0,0,0,0,11,-10,0,0,0,0,11,-100,-4,0,0,0,0,11,-10,0,0,0,0,11,-100,-4,0,0,0,0,11,-10,0,0,0,0,11,-100,-4,1,0,0,0,11,-9,13,0,0,0,0,11,-100,-4,1,0,0,0,11,-9,5,0,0,0,0,11,-100,-4,5,0,0,0,7,-8,7,0,0,0,0,0,11,-100,-4,7,0,0,0,0,13,-5,13,5,0,0,0,0,0,0,11,-100,-4,13,0,0,0,0,1,11,-1,13,11,5,0,0,7,5,0,0,0,0,3,13,-100,-5,3,0,0,0,0,0,0,0,0,0,3,13,-2,0,0,0,0,0,0,7,-100,-5,11,0,0,0,0,0,0,0,1,9,-4,0,0,0,0,0,0,0,-100,-6,13,5,1,0,1,3,9,-6,3,1,3,7,9,11,13,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-101 };
static int8_t lt21[] = { -100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-6,13,9,1,3,13,-5,13,1,0,0,0,0,1,3,9,-100,1,0,0,0,0,0,0,0,0,0,1,-5,1,0,0,0,0,0,0,0,0,9,-100,3,0,0,0,0,0,0,0,0,0,5,-5,3,0,0,0,0,0,0,0,0,13,-100,-1,9,3,0,0,0,0,0,5,13,-7,13,9,0,0,0,0,1,11,-100,-3,7,0,0,0,0,-11,7,0,0,5,-100,-4,0,0,0,0,9,-10,9,0,5,-100,-4,5,0,0,0,1,-10,5,0,11,-100,-4,11,0,0,0,0,9,-9,0,1,-100,-5,1,0,0,0,3,-8,9,0,7,-100,-5,7,0,0,0,0,13,-7,3,0,13,-100,-5,13,0,0,0,0,7,-6,13,0,3,-100,-6,3,0,0,0,1,-6,7,0,11,-100,-6,9,0,0,0,0,9,-5,0,1,-100,-6,13,0,0,0,0,3,-4,7,0,7,-100,-7,5,0,0,0,0,11,-3,1,0,13,-100,-7,11,0,0,0,0,1,-2,9,0,5,-100,-8,1,0,0,0,0,5,-1,1,0,11,-100,-8,7,0,0,0,0,0,0,0,3,-100,-8,13,0,0,0,0,0,0,0,9,-100,-9,3,0,0,0,0,0,1,-100,-9,9,0,0,0,0,0,7,-100,-10,0,0,0,0,0,13,-100,-10,5,0,0,0,1,-100,-10,13,1,0,0,7,-100,-11,11,1,5,-100,-100,-100,-100,-100,-100,-100,-100,-100,-101 };
static int8_t lt22[] = { -100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-29,13,-100,5,0,0,1,1,1,3,3,5,7,-3,7,0,0,0,0,0,0,0,0,0,11,-4,3,0,0,0,0,0,0,1,3,11,-100,5,0,0,0,0,0,0,0,1,7,-3,9,0,0,0,0,0,0,0,0,1,11,-4,9,1,0,0,0,0,0,0,1,13,-100,-1,13,5,0,0,0,0,0,13,-5,13,5,0,0,0,0,0,3,-8,9,0,0,0,0,5,-100,-3,5,0,0,0,0,-8,11,0,0,0,0,9,-9,9,0,0,9,-100,-4,1,0,0,0,13,-8,11,0,0,0,3,-10,0,3,-100,-4,7,0,0,0,11,-8,13,0,0,0,0,13,-8,9,0,11,-100,-4,13,0,0,0,7,-8,11,0,0,0,0,7,-8,1,1,-100,-5,5,0,0,1,-8,7,0,0,0,0,3,-8,5,11,-100,-5,11,0,0,0,9,-7,1,0,0,0,0,0,13,-100,-6,0,0,0,3,-6,9,0,3,13,0,0,0,7,-6,5,-100,-6,3,0,0,0,13,-5,1,0,11,-1,3,0,0,3,-6,1,-100,-6,9,0,0,0,9,-4,11,0,3,-2,7,0,0,0,13,-4,11,1,-100,-6,13,0,0,0,3,-4,5,0,9,-2,13,0,0,0,7,-4,5,3,-100,-7,3,0,0,0,13,-3,1,1,-4,0,0,0,1,-4,1,7,-100,-7,9,0,0,0,5,-2,13,0,7,-4,5,0,0,0,9,-2,9,0,13,-100,-8,1,0,0,0,13,-1,7,1,-5,11,0,0,0,1,-2,1,3,-100,-8,7,0,0,0,1,13,1,5,-6,1,0,0,0,13,9,0,9,-100,-8,13,0,0,0,0,0,0,11,-6,7,0,0,0,1,0,1,-100,-9,3,0,0,0,0,3,-7,13,0,0,0,0,0,9,-100,-9,9,0,0,0,0,5,-8,3,0,0,0,0,13,-100,-9,13,0,0,0,0,11,-8,9,0,0,0,1,-100,-10,3,0,0,0,-10,3,0,0,5,-100,-10,11,0,0,7,-10,13,1,1,13,-100,-11,11,11,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-101 };
static int8_t lt23[] = { -100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-16,13,13,-1,13,9,5,1,0,1,5,13,-100,-1,3,0,0,0,0,0,0,0,0,1,7,-4,1,0,0,0,0,0,0,0,0,0,1,-100,-1,1,0,0,0,0,0,0,0,0,1,11,-4,7,0,0,0,0,0,0,0,0,0,5,-100,-2,13,7,0,0,0,0,0,0,13,-6,13,5,0,0,0,0,5,9,13,-100,-4,13,3,0,0,0,0,3,-7,13,0,0,5,13,-100,-6,3,0,0,0,0,5,-6,7,0,7,-100,-7,3,0,0,0,0,11,-4,11,0,9,-100,-8,5,0,0,0,1,-3,11,0,7,-100,-9,3,0,0,0,1,11,11,0,7,-100,-9,13,1,0,0,0,0,0,7,-100,-10,13,1,0,0,0,0,9,-100,-11,11,0,0,0,0,1,-100,-12,0,0,0,0,0,7,-100,-11,9,0,0,0,0,0,0,11,-100,-10,9,0,5,13,3,0,0,0,1,13,-100,-9,11,0,3,-2,13,1,0,0,0,1,13,-100,-8,11,0,3,13,-3,13,1,0,0,0,1,13,-100,-7,9,0,1,13,-5,11,0,0,0,0,1,13,-100,-6,9,0,0,7,-7,9,0,0,0,0,1,11,-100,-5,5,0,0,0,13,-8,7,0,0,0,0,0,9,-100,-3,13,3,0,0,0,0,13,-8,13,0,0,0,0,0,0,5,-100,9,3,1,0,0,0,0,0,0,1,11,-6,11,1,0,0,0,0,0,0,0,1,3,13,-100,3,0,0,0,0,0,0,0,0,0,3,-6,11,5,3,1,0,0,0,1,1,3,5,-100,13,13,13,13,-100,-100,-100,-100,-100,-100,-100,-100,-100,-101 };
static int8_t lt24[] = { -100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-100,-1,13,13,-2,13,13,11,11,11,13,-6,11,11,11,11,11,11,11,11,13,-100,3,0,0,0,0,0,0,0,0,0,0,3,-4,1,0,0,0,0,0,0,0,0,1,-100,7,0,0,0,0,0,0,0,0,0,0,5,-4,3,0,0,0,0,0,0,0,0,9,-100,-2,11,5,0,0,0,0,0,0,11,-6,11,0,0,0,0,1,7,13,-100,-4,11,0,0,0,0,0,-8,9,0,0,1,13,-100,-5,7,0,0,0,0,13,-7,9,0,0,13,-100,-6,1,0,0,0,9,-7,5,0,5,-100,-6,7,0,0,0,3,-7,1,0,13,-100,-6,13,0,0,0,0,13,-5,11,0,1,-100,-7,5,0,0,0,7,-5,7,0,7,-100,-7,11,0,0,0,3,-5,1,0,11,-100,-8,1,0,0,0,13,-3,13,0,3,-100,-8,7,0,0,0,7,-3,7,0,9,-100,-8,13,0,0,0,3,-3,1,1,-100,-9,5,0,0,0,13,-1,9,0,7,-100,-9,11,0,0,0,3,13,1,0,13,-100,-10,1,0,0,0,0,0,3,-100,-10,9,0,0,0,0,0,9,-100,-11,1,0,0,0,1,-100,-11,5,0,0,0,7,-100,-11,9,0,0,0,13,-100,-11,13,0,0,3,-100,-12,0,0,9,-100,-12,0,1,-100,-11,13,0,7,-100,-11,7,0,11,-100,-11,1,0,-100,-2,7,0,1,7,-4,11,0,3,-100,-1,11,0,0,0,0,1,9,13,11,1,0,9,-100,-1,3,0,0,0,0,0,0,0,0,0,3,-100,-1,0,0,0,0,0,0,0,0,0,1,13,-100,-1,7,0,0,0,0,0,0,0,1,13,-100,-2,9,3,0,0,1,3,7,-100,-101 };
static int8_t *lt[] = { lt0,lt1,lt2,lt3,lt0,lt5,lt0,lt7,lt8,lt9,lt10,lt11,lt12,lt13,lt14,lt15,lt16,lt17,lt18,lt19,lt20,lt21,lt22,lt23,lt24, };
const int gifsize=17646;
void makegif(unsigned char im[70*200], unsigned char gif[17646]) {
// tag ; widthxheight ; GCT:0:0:7 ; bgcolor + aspect // GCT
// Image Separator // left x top // widthxheight // Flags
// LZW code size
memcpy(gif,"GIF89a" "\xc8\0\x46\0" "\x83" "\0\0"
"\x00\x00\x00"
"\x10\x10\x10"
"\x20\x20\x20"
"\x30\x30\x30"
"\x40\x40\x40"
"\x50\x50\x50"
"\x60\x60\x60"
"\x70\x70\x70"
"\x80\x80\x80"
"\x90\x90\x90"
"\xa0\xa0\xa0"
"\xb0\xb0\xb0"
"\xc0\xc0\xc0"
"\xd0\xd0\xd0"
"\xe0\xe0\xe0"
"\xff\xff\xff"
"," "\0\0\0\0" "\xc8\0\x46\0" "\0" "\x04",13+48+10+1);
int x,y;
unsigned char *i=im;
unsigned char *p=gif+13+48+10+1;
for(y=0;y<70;y++) {
*p++=250; // Data length 5*50=250
for(x=0;x<50;x++)
{
unsigned char a=i[0]>>4,b=i[1]>>4,c=i[2]>>4,d=i[3]>>4;
p[0]=16|(a<<5); // bbb10000
p[1]=(a>>3)|64|(b<<7); // b10000xb
p[2]=b>>1; // 0000xbbb
p[3]=1|(c<<1); // 00xbbbb1
p[4]=4|(d<<3); // xbbbb100
i+=4;
p+=5;
}
}
// Data length // End of LZW (b10001) // Terminator // GIF End
memcpy(gif+gifsize-4,"\x01" "\x11" "\x00" ";",4);
}
static const int8_t sw[200]={0, 4, 8, 12, 16, 20, 23, 27, 31, 35, 39, 43, 47, 50, 54, 58, 61, 65, 68, 71, 75, 78, 81, 84, 87, 90, 93, 96, 98, 101, 103, 105, 108, 110, 112, 114, 115, 117, 119, 120, 121, 122, 123, 124, 125, 126, 126, 127, 127, 127, 127, 127, 127, 127, 126, 126, 125, 124, 123, 122, 121, 120, 119, 117, 115, 114, 112, 110, 108, 105, 103, 101, 98, 96, 93, 90, 87, 84, 81, 78, 75, 71, 68, 65, 61, 58, 54, 50, 47, 43, 39, 35, 31, 27, 23, 20, 16, 12, 8, 4, 0, -4, -8, -12, -16, -20, -23, -27, -31, -35, -39, -43, -47, -50, -54, -58, -61, -65, -68, -71, -75, -78, -81, -84, -87, -90, -93, -96, -98, -101, -103, -105, -108, -110, -112, -114, -115, -117, -119, -120, -121, -122, -123, -124, -125, -126, -126, -127, -127, -127, -127, -127, -127, -127, -126, -126, -125, -124, -123, -122, -121, -120, -119, -117, -115, -114, -112, -110, -108, -105, -103, -101, -98, -96, -93, -90, -87, -84, -81, -78, -75, -71, -68, -65, -61, -58, -54, -50, -47, -43, -39, -35, -31, -27, -23, -20, -16, -12, -8, -4};
#define MAX(x,y) ((x>y)?(x):(y))
static int letter(int n, int pos, unsigned char im[70*200], unsigned char swr[200], uint8_t s1, uint8_t s2) {
int8_t *p=lt[n];
unsigned char *r=im+200*16+pos;
unsigned char *i=r;
int sk1=s1+pos;
int sk2=s2+pos;
int mpos=pos;
int row=0;
for(;*p!=-101;p++) {
if(*p<0) {
if(*p==-100) { r+=200; i=r; sk1=s1+pos; row++; continue; }
i+=-*p;
continue;
}
if(sk1>=200) sk1=sk1%200;
int skew=sw[sk1]/16;
sk1+=(swr[pos+i-r]&0x1)+1;
if(sk2>=200) sk2=sk2%200;
int skewh=sw[sk2]/70;
sk2+=(swr[row]&0x1);
unsigned char *x=i+skew*200+skewh;
mpos=MAX(mpos,pos+i-r);
if((x-im)<70*200) *x=(*p)<<4;
i++;
}
return mpos;
}
#define NDOTS 100
uint32_t dr[NDOTS];
static void line(unsigned char im[70*200], unsigned char swr[200], uint8_t s1) {
int x;
int sk1=s1;
for(x=0;x<199;x++) {
if(sk1>=200) sk1=sk1%200;
int skew=sw[sk1]/16;
sk1+=swr[x]&0x3+1;
unsigned char *i= im+(200*(45+skew)+x);
i[0]=0; i[1]=0; i[200]=0; i[201]=0;
}
}
static void dots(unsigned char im[70*200]) {
int n;
for(n=0;n<NDOTS;n++) {
uint32_t v=dr[n];
unsigned char *i=im+v%(200*67);
i[0]=0xff;
i[1]=0xff;
i[2]=0xff;
i[200]=0xff;
i[201]=0xff;
i[202]=0xff;
}
}
static void blur(unsigned char im[70*200]) {
unsigned char *i=im;
int x,y;
for(y=0;y<68;y++) {
for(x=0;x<198;x++) {
unsigned int c11=*i,c12=i[1],c21=i[200],c22=i[201];
*i++=((c11+c12+c21+c22)/4);
}
}
}
static void filter(unsigned char im[70*200]) {
unsigned char om[70*200];
unsigned char *i=im;
unsigned char *o=om;
memset(om,0xff,sizeof(om));
int x,y;
for(y=0;y<70;y++) {
for(x=4;x<200-4;x++) {
if(i[0]>0xf0 && i[1]<0xf0) { o[0]=0; o[1]=0; }
else if(i[0]<0xf0 && i[1]>0xf0) { o[0]=0; o[1]=0; }
i++;
o++;
}
}
memmove(im,om,sizeof(om));
}
static const char *letters="abcdafahijklmnopqrstuvwxyz";
void captcha(unsigned char im[70*200], unsigned char l[6]) {
unsigned char swr[200];
uint8_t s1, s2;
int i = 0;
for (i = 0; i < 200; i++)
swr[i] = rand() % 256;
for (i = 0; i < NDOTS*4; i++)
((unsigned char*)dr)[i] = rand() % 256;
s1 = rand() % 256;
s2 = rand() % 256;
memset(im,0xff,200*70); s1=s1&0x7f; s2=s2&0x3f; l[0]%=25; l[1]%=25; l[2]%=25; l[3]%=25; l[4]%=25; l[5]=0;
int p=30; p=letter(l[0],p,im,swr,s1,s2); p=letter(l[1],p,im,swr,s1,s2); p=letter(l[2],p,im,swr,s1,s2); p=letter(l[3],p,im,swr,s1,s2); letter(l[4],p,im,swr,s1,s2);
dots(im); blur(im); filter(im); line(im,swr,s1);
l[0]=letters[l[0]]; l[1]=letters[l[1]]; l[2]=letters[l[2]]; l[3]=letters[l[3]]; l[4]=letters[l[4]];
}
#ifdef CAPTCHA
int main() {
char l[6];
unsigned char im[70*200];
unsigned char gif[gifsize];
captcha(im,l);
makegif(im,gif);
write(1,gif,gifsize);
write(2,l,5);
return 0;
}
#endif
/*
http://brokestream.com/captcha.html
Copyright (C) 2009 Ivan Tikhonov
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
Ivan Tikhonov, kefeer@brokestream.com
*/

View File

@@ -0,0 +1,131 @@
Creative Commons Legal Code
CC0 1.0 Universal
Official translations of this legal tool are available
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL
SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN ATTORNEY-CLIENT
RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS.
CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE USE OF THIS DOCUMENT OR THE
INFORMATION OR WORKS PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES
RESULTING FROM THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
HEREUNDER.
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator and
subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for the
purpose of contributing to a commons of creative, cultural and scientific works
("Commons") that the public can reliably and without fear of later claims of
infringement build upon, modify, incorporate in other works, reuse and
redistribute as freely as possible in any form whatsoever and for any purposes,
including without limitation commercial purposes. These owners may contribute
to the Commons to promote the ideal of a free culture and the further
production of creative, cultural and scientific works, or to gain reputation
or greater distribution for their Work in part through the use and efforts of
others.
For these and/or other purposes and motivations, and without any expectation
of additional consideration or compensation, the person associating CC0 with a
Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
and publicly distribute the Work under its terms, with knowledge of his or her
Copyright and Related Rights in the Work and the meaning and intended legal
effect of CC0 on those rights.
1. Copyright and Related Rights.
A Work made available under CC0 may be protected by copyright and related
or neighboring rights ("Copyright and Related Rights"). Copyright and
Related Rights include, but are not limited to, the following:
the right to reproduce, adapt, distribute, perform, display, communicate,
and translate a Work;
moral rights retained by the original author(s) and/or performer(s);
publicity and privacy rights pertaining to a person's image or likeness
depicted in a Work;
rights protecting against unfair competition in regards to a Work, subject
to the limitations in paragraph 4(a), below;
rights protecting the extraction, dissemination, use and reuse of data in
a Work;
database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation thereof,
including any amended or successor version of such directive); and
other similar, equivalent or corresponding rights throughout the world
based on applicable law or treaty, and any national implementations
thereof.
2. Waiver.
To the greatest extent permitted by, but not in contravention of, applicable
law, Affirmer hereby overtly, fully, permanently, irrevocably and
unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
and Related Rights and associated claims and causes of action, whether now
known or unknown (including existing as well as future claims and causes of
action), in the Work (i) in all territories worldwide, (ii) for the maximum
duration provided by applicable law or treaty (including future time
extensions), (iii) in any current or future medium and for any number of
copies, and (iv) for any purpose whatsoever, including without limitation
commercial, advertising or promotional purposes (the "Waiver"). Affirmer
makes the Waiver for the benefit of each member of the public at large and
to the detriment of Affirmer's heirs and successors, fully intending that
such Waiver shall not be subject to revocation, rescission, cancellation,
termination, or any other legal or equitable action to disrupt the quiet
enjoyment of the Work by the public as contemplated by Affirmer's express
Statement of Purpose.
3. Public License Fallback.
Should any part of the Waiver for any reason be judged legally invalid or
ineffective under applicable law, then the Waiver shall be preserved to the
maximum extent permitted taking into account Affirmer's express Statement of
Purpose. In addition, to the extent the Waiver is so judged Affirmer hereby
grants to each affected person a royalty-free, non transferable, non
sublicensable, non exclusive, irrevocable and unconditional license to
exercise Affirmer's Copyright and Related Rights in the Work (i) in all
territories worldwide, (ii) for the maximum duration provided by applicable
law or treaty (including future time extensions), (iii) in any current or
future medium and for any number of copies, and (iv) for any purpose
whatsoever, including without limitation commercial, advertising or
promotional purposes (the "License"). The License shall be deemed effective
as of the date CC0 was applied by Affirmer to the Work. Should any part of
the License for any reason be judged legally invalid or ineffective under
applicable law, such partial invalidity or ineffectiveness shall not
invalidate the remainder of the License, and in such case Affirmer hereby
affirms that he or she will not (i) exercise any of his or her remaining
Copyright and Related Rights in the Work or (ii) assert any associated
claims and causes of action with respect to the Work, in either case
contrary to Affirmer's express Statement of Purpose.
4. Limitations and Disclaimers.
No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
Affirmer offers the Work as-is and makes no representations or warranties
of any kind concerning the Work, express, implied, statutory or otherwise,
including without limitation warranties of title, merchantability, fitness
for a particular purpose, non infringement, or the absence of latent or
other defects, accuracy, or the present or absence of errors, whether or not
discoverable, all to the greatest extent permissible under applicable law.
Affirmer disclaims responsibility for clearing rights of other persons that
may apply to the Work or any use thereof, including without limitation any
person's Copyright and Related Rights in the Work. Further, Affirmer
disclaims responsibility for obtaining any necessary consents, permissions
or other rights required for any use of the Work.
Affirmer understands and acknowledges that Creative Commons is not a party
to this document and has no duty or obligation with respect to this CC0 or
use of the Work.

View File

@@ -0,0 +1,199 @@
# smtp-client
This is an SMTP client library written in C which can get included
directly into another program.
This library has been released into the public domain using
[CC0](https://creativecommons.org/publicdomain/zero/1.0/).
Official repository location:
[www.somnisoft.com/smtp-client](https://www.somnisoft.com/smtp-client)
## Feature list
* C89
* Cross-platform (POSIX, BSD, MacOS, Windows)
* Send attachments
* Send custom email headers
* Specify multiple TO, CC, and BCC recipients
* Simple API and simple error handling (see Examples section below)
* Optional OpenSSL TLS connection and authentication methods
* Test cases with 100% code and branch coverage
* Doxygen with 100% documentation including the test code
* Free software (permissive - CC0)
Supports the following connection methods:
* No encryption
* STARTTLS (requires OpenSSL)
* TLS direct connection (requires OpenSSL)
Supports the following authentication methods:
* none
* PLAIN
* LOGIN
* CRAM-MD5 (requires OpenSSL)
To include the library into your application, simply copy the src/smtp.h and
src/smtp.c files into your project directory. Then include the smtp.h header
into your C file, compile smtp.c, and include the resulting object file into
the build system.
## Examples
The following example code demonstrates how to use the library.
```C
#include <stdio.h>
#include "smtp.h"
#define MAIL_SERVER "mail.example.com"
#define MAIL_PORT "587"
#define MAIL_CONNECTION_SECURITY SMTP_SECURITY_STARTTLS
#define MAIL_FLAGS (SMTP_DEBUG | \
SMTP_NO_CERT_VERIFY) /* Do not verify cert. */
#define MAIL_CAFILE NULL
#define MAIL_AUTH SMTP_AUTH_PLAIN
#define MAIL_USER "mail@example.com"
#define MAIL_PASS "password"
#define MAIL_FROM "mail@example.com"
#define MAIL_FROM_NAME "From Name"
#define MAIL_SUBJECT "Subject Line"
#define MAIL_BODY "Email Body"
#define MAIL_TO "to@example.com"
#define MAIL_TO_NAME "To Name"
int main(void)
{
struct smtp *smtp;
int rc;
rc = smtp_open(MAIL_SERVER,
MAIL_PORT,
MAIL_CONNECTION_SECURITY,
MAIL_FLAGS,
MAIL_CAFILE,
&smtp);
rc = smtp_auth(smtp,
MAIL_AUTH,
MAIL_USER,
MAIL_PASS);
rc = smtp_address_add(smtp,
SMTP_ADDRESS_FROM,
MAIL_FROM,
MAIL_FROM_NAME);
rc = smtp_address_add(smtp,
SMTP_ADDRESS_TO,
MAIL_TO,
MAIL_TO_NAME);
rc = smtp_header_add(smtp,
"Subject",
MAIL_SUBJECT);
rc = smtp_attachment_add_mem(smtp,
"test.txt",
"Test email attachment.",
-1);
rc = smtp_mail(smtp,
MAIL_BODY);
rc = smtp_close(smtp);
if(rc != SMTP_STATUS_OK){
fprintf(stderr, "smtp failed: %s\n", smtp_status_code_errstr(rc));
return 1;
}
return 0;
}
```
Place the code snippet above into a file named 'test.c' and change each #define
to the appropriate values for your mail server. Then copy smtp.c and smtp.h
into the same directory and run the following commands to compile with OpenSSL
support.
cc -DSMTP_OPENSSL smtp.c -c -o smtp.o
cc -DSMTP_OPENSSL test.c -c -o test.o
cc test.o smtp.o -o smtp_test -lssl -lcrypto
If you do not need OpenSSL support, remove the -DSMTP_OPENSSL and the
-lssl and -lcrypto arguments. The commands as above should create an
executable called 'smtp_test' which can send a test email using the specified
mail server.
A minimum amount of error checking has been included. Note that in the above
example, the program checks for an error at the end of the mail session after
calling smtp_close. We can do this because if an error occurs in any of the
prior functions, the error will continue to propagate through any future
function calls until either closing the SMTP context using smtp_close or by
resetting the error condition using smtp_status_code_clear.
The following example demonstrates how to send an HTML email by overriding the
Content-Type header. When overriding this header, any attachments added using
the smtp_attachment_add\* functions will get ignored. The application must
generate the appropriate MIME sections (if needed) when overriding this
header.
```C
#include <stdio.h>
#include "smtp.h"
#define MAIL_SERVER "localhost"
#define MAIL_PORT "25"
#define MAIL_CONNECTION_SECURITY SMTP_SECURITY_NONE
#define MAIL_FLAGS SMTP_DEBUG
#define MAIL_CAFILE NULL
#define MAIL_AUTH SMTP_AUTH_NONE
#define MAIL_USER "mail@somnisoft.com"
#define MAIL_PASS "password"
#define MAIL_FROM "mail@somnisoft.com"
#define MAIL_FROM_NAME "From Name"
#define MAIL_SUBJECT "Subject Line"
#define MAIL_TO "mail@somnisoft.com"
#define MAIL_TO_NAME "To Name"
int main(void){
struct smtp *smtp;
enum smtp_status_code rc;
const char *const email_body =
"<html>\n"
" <head><title>HTML Email</title></head>\n"
" <body>\n"
" <h1>H1</h1>\n"
" <h2>H2</h1>\n"
" <h3>H3</h1>\n"
" <h4>H4</h1>\n"
" <h5>H5</h1>\n"
" <h6>H6</h1>\n"
" </body>\n"
"</html>\n";
smtp_open(MAIL_SERVER,
MAIL_PORT,
MAIL_CONNECTION_SECURITY,
MAIL_FLAGS,
MAIL_CAFILE,
&smtp);
smtp_auth(smtp,
MAIL_AUTH,
MAIL_USER,
MAIL_PASS);
smtp_address_add(smtp,
SMTP_ADDRESS_FROM,
MAIL_FROM,
MAIL_FROM_NAME);
smtp_address_add(smtp,
SMTP_ADDRESS_TO,
MAIL_TO,
MAIL_TO_NAME);
smtp_header_add(smtp,
"Subject",
MAIL_SUBJECT);
smtp_header_add(smtp,
"Content-Type",
"text/html");
smtp_mail(smtp, email_body);
rc = smtp_close(smtp);
if(rc != SMTP_STATUS_OK){
fprintf(stderr, "smtp failed: %s\n", smtp_status_code_errstr(rc));
return 1;
}
return 0;
}
```
## Technical Documentation
See the [Technical Documentation](
https://www.somnisoft.com/smtp-client/technical-documentation/index.html)
generated from Doxygen.

View File

@@ -0,0 +1,117 @@
/**
* @file
* @brief SMTPMail class wrapper for smtp-client library.
* @author James Humphrey (mail@somnisoft.com)
* @version 1.00
*
* Thin CPP wrapper class around the smtp-client C library.
*
* This software has been placed into the public domain using CC0.
*/
#include "SMTPMail.h"
SMTPMailException::SMTPMailException(enum smtp_status_code status_code){
this->status_code = status_code;
}
const char*
SMTPMailException::what() const noexcept {
return smtp_status_code_errstr(this->status_code);
}
SMTPMail::SMTPMail(void){
}
SMTPMail::~SMTPMail(void){
}
void SMTPMail::open(const char *const server,
const char *const port,
enum smtp_connection_security connection_security,
enum smtp_flag flags,
const char *const cafile){
this->rc = smtp_open(server,
port,
connection_security,
flags,
cafile,
&this->smtp);
this->throw_bad_status_code();
}
void SMTPMail::auth(enum smtp_authentication_method auth_method,
const char *const user,
const char *const pass){
this->rc = smtp_auth(this->smtp, auth_method, user, pass);
this->throw_bad_status_code();
}
void SMTPMail::mail(const char *const body){
this->rc = smtp_mail(this->smtp, body);
this->throw_bad_status_code();
}
void SMTPMail::close(void){
this->rc = smtp_close(this->smtp);
this->throw_bad_status_code();
}
int SMTPMail::status_code_get(void){
return smtp_status_code_get(this->smtp);
}
void SMTPMail::status_code_set(enum smtp_status_code new_status_code){
this->rc = smtp_status_code_set(this->smtp, new_status_code);
this->throw_bad_status_code();
}
void SMTPMail::header_add(const char *const key,
const char *const value){
this->rc = smtp_header_add(this->smtp, key, value);
this->throw_bad_status_code();
}
void SMTPMail::header_clear_all(void){
smtp_header_clear_all(this->smtp);
}
void SMTPMail::address_add(enum smtp_address_type type,
const char *const email,
const char *const name){
this->rc = smtp_address_add(this->smtp, type, email, name);
this->throw_bad_status_code();
}
void SMTPMail::address_clear_all(void){
smtp_address_clear_all(this->smtp);
}
void SMTPMail::attachment_add_path(const char *const name,
const char *const path){
this->rc = smtp_attachment_add_path(this->smtp, name, path);
this->throw_bad_status_code();
}
void SMTPMail::attachment_add_fp(const char *const name,
FILE *fp){
this->rc = smtp_attachment_add_fp(this->smtp, name, fp);
this->throw_bad_status_code();
}
void SMTPMail::attachment_add_mem(const char *const name,
const void *const data,
size_t datasz){
this->rc = smtp_attachment_add_mem(this->smtp, name, data, datasz);
this->throw_bad_status_code();
}
void SMTPMail::attachment_clear_all(void){
smtp_attachment_clear_all(this->smtp);
}
void SMTPMail::throw_bad_status_code(void){
if(this->rc != SMTP_STATUS_OK){
throw SMTPMailException(this->rc);
}
}

View File

@@ -0,0 +1,243 @@
/**
* @file
* @brief SMTPMail class wrapper for smtp-client library.
* @author James Humphrey (mail@somnisoft.com)
* @version 1.00
*
* Thin CPP wrapper class around the smtp-client C library.
*
* This software has been placed into the public domain using CC0.
*/
#ifndef SMTP_MAIL_H
#define SMTP_MAIL_H
#include <exception>
#include "smtp.h"
/**
* @class SMTPMailException
*
* This exception will get thrown whenever an SMTP client function fails.
*/
class SMTPMailException : public std::exception{
public:
/**
* Create the exception with the corresponding @p status_code.
*
* @param[in] status_code An error status code returned from a previous call
* to an smtp-client library function.
*/
SMTPMailException(enum smtp_status_code status_code);
/**
* Get a description of the smtp-client status code that caused
* this exception.
*
* @return Null-terminated string describing the smtp-client status code.
*/
virtual const char* what() const noexcept;
private:
/**
* The status code generated by any of the smtp-client library functions.
*/
enum smtp_status_code status_code;
};
/**
* @class SMTPMail
*
* Thin CPP wrapper class over the smtp-client C library.
*/
class SMTPMail{
public:
/**
* Create the @ref SMTPMail object.
*/
SMTPMail(void);
/**
* Free the @ref SMTPMail object.
*/
~SMTPMail(void);
/**
* Open a connection to an SMTP server.
*
* See @ref smtp_open.
*
* @param[in] server Server name or IP address.
* @param[in] port Server port number.
* @param[in] connection_security See @ref smtp_connection_security.
* @param[in] flags See @ref smtp_flag.
* @param[in] cafile Path to certificate file, or NULL to use
* certificates in the default path.
*/
void open(const char *const server,
const char *const port,
enum smtp_connection_security connection_security,
enum smtp_flag flags,
const char *const cafile);
/**
* Authenticate the user using one of the methods listed in
* @ref smtp_authentication_method.
*
* See @ref smtp_auth.
*
* @param[in] auth_method See @ref smtp_authentication_method.
* @param[in] user Server authentication user name.
* @param[in] pass Server authentication user password.
*/
void auth(enum smtp_authentication_method auth_method,
const char *const user,
const char *const pass);
/**
* Sends an email using the addresses, attachments, and headers defined
* in the current SMTP context.
*
* See @ref smtp_mail.
*
* @param[in] body Null-terminated string to send in the email body.
*/
void mail(const char *const body);
/**
* Close the SMTP connection and frees all resources held by the
* SMTP context.
*
* See @ref smtp_close.
*/
void close(void);
/**
* Get the current status/error code described in @ref smtp_status_code.
*
* See @ref smtp_status_code_get.
*
* @return @ref smtp_status_code.
*/
int status_code_get(void);
/**
* Set the error status of the SMTP client context.
*
* See @ref smtp_status_code_set.
*
* @param[in] new_status_code See @ref smtp_status_code.
*/
void status_code_set(enum smtp_status_code new_status_code);
/**
* Add a key/value header to the header list in the SMTP context.
*
* See @ref smtp_header_add.
*
* @param[in] key Key name for new header. It must consist only of
* printable US-ASCII characters except colon.
* @param[in] value Value for new header. It must consist only of printable
* US-ASCII, space, or horizontal tab. If set to NULL,
* this will prevent the header from printing out.
*/
void header_add(const char *const key,
const char *const value);
/**
* Free all memory related to email headers.
*
* See @ref smtp_header_clear_all.
*/
void header_clear_all(void);
/**
* Add a FROM, TO, CC, or BCC address destination to this SMTP context.
*
* See @ref smtp_address_add.
*
* @param[in] type See @ref smtp_address_type.
* @param[in] email The email address of the party. Must consist only of
* printable characters excluding the angle brackets
* (<) and (>).
* @param[in] name Name or description of the party. Must consist only of
* printable characters, excluding the quote characters. If
* set to NULL, no name will get associated with this email.
*/
void address_add(enum smtp_address_type type,
const char *const email,
const char *const name);
/**
* Free all memory related to the address list.
*
* See @ref smtp_address_clear_all.
*/
void address_clear_all(void);
/**
* Add a file attachment from a path.
*
* See @ref smtp_attachment_add_mem.
*
* @param[in] name Filename of the attachment shown to recipients.
* @param[in] path Path of file location to read from.
*/
void attachment_add_path(const char *const name,
const char *const path);
/**
* Add an attachment using a file pointer.
*
* See @ref smtp_attachment_add_fp.
*
* @param[in] name Filename of the attachment shown to recipients.
* @param[in] fp File pointer already opened by the caller.
*/
void attachment_add_fp(const char *const name,
FILE *fp);
/**
* Add an attachment with the data pulled from memory.
*
* See @ref smtp_attachment_add_mem.
*
* @param[in] name Filename of the attachment shown to recipients. Must
* consist only of printable characters excluding the
* quote characters (') and ("), or the space character
* ( ).
* @param[in] data Raw attachment data stored in memory.
* @param[in] datasz Number of bytes in @p data, or -1 if data
* null-terminated.
*/
void attachment_add_mem(const char *const name,
const void *const data,
size_t datasz);
/**
* Remove all attachments from the SMTP client context.
*
* See @ref smtp_attachment_clear_all.
*/
void attachment_clear_all(void);
private:
/**
* SMTP client context.
*/
struct smtp *smtp;
/**
* Store the last smtp-client library function return code.
*/
enum smtp_status_code rc;
/**
* Throw @ref SMTPMailException if the last smtp-client library function
* failed.
*/
void throw_bad_status_code(void);
};
#endif /* SMTP_MAIL_H */

View File

@@ -0,0 +1,558 @@
/**
* @file
* @brief POSIX mailx utility.
* @author James Humphrey (mail@somnisoft.com)
* @version 1.00
*
* Implementation of POSIX mailx utility in send mode.
*
* mailx [-s subject] [[-S option]...] [[-a attachment]...] address...
*
* This software has been placed into the public domain using CC0.
*/
/**
* Required on some POSIX systems to include some standard functions.
*/
#define _POSIX_C_SOURCE 200809L
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "smtp.h"
/**
* Stores the to and from email addresses.
*/
struct mailx_address{
/**
* See @ref smtp_address_type.
*/
enum smtp_address_type address_type;
/**
* Email address.
*/
char email[1000];
};
/**
* The attachment name and path stored for each attachment to send to the
* recipient.
*/
struct mailx_attachment{
/**
* File name for this attachment to display to the recipient.
*/
char name[1000];
/**
* Local file path pointing to the attachment to send.
*/
char path[1000];
};
/**
* The mailx context structure containing the parameters for setting up the
* SMTP connection and sending the email.
*/
struct mailx{
/**
* SMTP client context.
*/
struct smtp *smtp;
/**
* Email subject line.
*/
const char *subject;
/**
* Email body text.
*/
char *body;
/**
* SMTP server name or IP address.
*/
char *server;
/**
* SMTP server port number.
*/
char *port;
/**
* SMTP account user name used for authenticating.
*/
char *user;
/**
* SMTP account password used for authenticating.
*/
char *pass;
/**
* From email address or name.
*/
char *from;
/**
* Determine if using a TLS encrypted connection or plain socket.
*/
enum smtp_connection_security connection_security;
/**
* SMTP user account authentication method.
*/
enum smtp_authentication_method auth_method;
/**
* Miscellaneous control flags for smtp-lib.
*
* See @ref smtp_flag for more details.
*/
enum smtp_flag smtp_flags;
/**
* List of email addresses to send to.
*/
struct mailx_address *address_list;
/**
* Number of email addresses in @ref address_list.
*/
size_t num_address;
/**
* List of files to attach in the email.
*/
struct mailx_attachment *attachment_list;
/**
* Number of attachments in @ref attachment_list.
*/
size_t num_attachment;
};
/**
* Read the entire contents of a file stream and store the data into a
* dynamically allocated buffer.
*
* @param[in] stream File stream already opened by the caller.
* @param[out] bytes_read Number of bytes stored in the return buffer.
* @retval char* A dynamically allocated buffer which contains the entire
* contents of @p stream. The caller must free this memory
* when done.
* @retval NULL Memory allocation or file read error.
*/
static char *
smtp_ffile_get_contents(FILE *stream,
size_t *bytes_read){
char *read_buf;
size_t bufsz;
char *new_buf;
const size_t BUFSZ_INCREMENT = 512;
read_buf = NULL;
bufsz = 0;
if(bytes_read){
*bytes_read = 0;
}
do{
size_t bytes_read_loop;
if((new_buf = realloc(read_buf, bufsz + BUFSZ_INCREMENT)) == NULL){
free(read_buf);
return NULL;
}
read_buf = new_buf;
bufsz += BUFSZ_INCREMENT;
bytes_read_loop = fread(&read_buf[bufsz - BUFSZ_INCREMENT],
sizeof(char),
BUFSZ_INCREMENT,
stream);
if(bytes_read){
*bytes_read += bytes_read_loop;
}
if(ferror(stream)){
free(read_buf);
return NULL;
}
} while(!feof(stream));
return read_buf;
}
/**
* Append this email to the list of email addresses to send to.
*
* @param[in] mailx Append the email address into this mailx context.
* @param[in] address_type See @ref smtp_address_type.
* @param[in] email Email address to send to.
*/
static void
mailx_address_append(struct mailx *const mailx,
enum smtp_address_type address_type,
const char *const email){
struct mailx_address *new_address;
size_t new_address_list_sz;
mailx->num_address += 1;
new_address_list_sz = mailx->num_address * sizeof(*mailx->address_list);
if((mailx->address_list = realloc(mailx->address_list,
new_address_list_sz)) == NULL){
err(1, "realloc");
}
new_address = &mailx->address_list[mailx->num_address - 1];
new_address->address_type = address_type;
strncpy(new_address->email, email, sizeof(new_address->email));
new_address->email[sizeof(new_address->email) - 1] = '\0';
}
/**
* Send the email using the configuration options in the @p mailx context.
*
* @param[in] mailx Email context.
*/
static void
mailx_send(struct mailx *const mailx){
int rc;
size_t i;
const struct mailx_address *address;
const struct mailx_attachment *attachment;
smtp_open(mailx->server,
mailx->port,
mailx->connection_security,
mailx->smtp_flags,
NULL,
&mailx->smtp);
smtp_auth(mailx->smtp,
mailx->auth_method,
mailx->user,
mailx->pass);
for(i = 0; i < mailx->num_address; i++){
address = &mailx->address_list[i];
smtp_address_add(mailx->smtp, address->address_type, address->email, NULL);
}
for(i = 0; i < mailx->num_attachment; i++){
attachment = &mailx->attachment_list[i];
smtp_attachment_add_path(mailx->smtp, attachment->name, attachment->path);
}
smtp_header_add(mailx->smtp, "Subject", mailx->subject);
smtp_mail(mailx->smtp, mailx->body);
rc = smtp_close(mailx->smtp);
if(rc != SMTP_STATUS_OK){
errx(1, "%s", smtp_status_code_errstr(rc));
}
}
/**
* Attach a file to the @p mailx context.
*
* @param[in] mailx Store the attachment details into this mailx context.
* @param[in] filename File name to display to the recipient.
* @param[in] path Local path of file to attach.
*/
static void
mailx_append_attachment(struct mailx *const mailx,
const char *const filename,
const char *const path){
struct mailx_attachment *new_attachment;
size_t new_attachment_list_sz;
if(filename == NULL || path == NULL){
errx(1, "must provide attachment with valid name:path");
}
new_attachment_list_sz = (mailx->num_attachment + 1) *
sizeof(*mailx->attachment_list);
if((mailx->attachment_list = realloc(mailx->attachment_list,
new_attachment_list_sz)) == NULL){
err(1, "realloc: attachment list");
}
new_attachment = &mailx->attachment_list[mailx->num_attachment];
mailx->num_attachment += 1;
strncpy(new_attachment->name, filename, sizeof(new_attachment->name));
new_attachment->name[sizeof(new_attachment->name) - 1] = '\0';
strncpy(new_attachment->path, path, sizeof(new_attachment->path));
new_attachment->path[sizeof(new_attachment->path) - 1] = '\0';
}
/**
* Parse the file name and path and attach it to the @p mailx context.
*
* @param[in] mailx Store the attachment details into this mailx context.
* @param[in] attach_arg String with format: 'filename:filepath'.
*/
static void
mailx_append_attachment_arg(struct mailx *const mailx,
const char *const attach_arg){
char *attach_arg_dup;
char *filename;
char *filepath;
if((attach_arg_dup = strdup(attach_arg)) == NULL){
err(1, "strdup: %s", attach_arg);
}
filename = strtok(attach_arg_dup, ":");
filepath = strtok(NULL, ":");
mailx_append_attachment(mailx, filename, filepath);
free(attach_arg_dup);
}
/**
* Parses the -S option which contains a key/value pair separated by an '='
* character.
*
* @param[in] mailx Store the results of the option parsing into the relevant
* field in this mailx context.
* @param[in] option String containing key/value option to parse.
*/
static void
mailx_parse_smtp_option(struct mailx *const mailx,
const char *const option){
char *optdup;
char *opt_key;
char *opt_value;
int rc;
rc = 0;
if((optdup = strdup(option)) == NULL){
err(1, "strdup: option: %s", option);
}
if((opt_key = strtok(optdup, "=")) == NULL){
errx(1, "strtok: %s", optdup);
}
opt_value = strtok(NULL, "=");
if(strcmp(opt_key, "smtp-security") == 0){
if(strcmp(opt_value, "none") == 0){
mailx->connection_security = SMTP_SECURITY_NONE;
}
#ifdef SMTP_OPENSSL
else if(strcmp(opt_value, "tls") == 0){
mailx->connection_security = SMTP_SECURITY_TLS;
}
else if(strcmp(opt_value, "starttls") == 0){
mailx->connection_security = SMTP_SECURITY_STARTTLS;
}
#endif /* SMTP_OPENSSL */
else{
rc = -1;
}
}
else if(strcmp(opt_key, "smtp-auth") == 0){
if(strcmp(opt_value, "none") == 0){
mailx->auth_method = SMTP_AUTH_NONE;
}
else if(strcmp(opt_value, "plain") == 0){
mailx->auth_method = SMTP_AUTH_PLAIN;
}
else if(strcmp(opt_value, "login") == 0){
mailx->auth_method = SMTP_AUTH_LOGIN;
}
#ifdef SMTP_OPENSSL
else if(strcmp(opt_value, "cram-md5") == 0){
mailx->auth_method = SMTP_AUTH_CRAM_MD5;
}
#endif /* SMTP_OPENSSL */
else{
rc = -1;
}
}
else if(strcmp(opt_key, "smtp-flag") == 0){
if(strcmp(opt_value, "debug") == 0){
mailx->smtp_flags |= SMTP_DEBUG;
}
else if(strcmp(opt_value, "no-cert-verify") == 0){
mailx->smtp_flags |= SMTP_NO_CERT_VERIFY;
}
else{
rc = -1;
}
}
else if(strcmp(opt_key, "smtp-server") == 0){
if((mailx->server = strdup(opt_value)) == NULL){
err(1, "strdup");
}
}
else if(strcmp(opt_key, "smtp-port") == 0){
if((mailx->port = strdup(opt_value)) == NULL){
err(1, "strdup");
}
}
else if(strcmp(opt_key, "smtp-user") == 0){
if((mailx->user = strdup(opt_value)) == NULL){
err(1, "strdup");
}
}
else if(strcmp(opt_key, "smtp-pass") == 0){
if((mailx->pass = strdup(opt_value)) == NULL){
err(1, "strdup");
}
}
else if(strcmp(opt_key, "smtp-from") == 0){
if((mailx->from = strdup(opt_value)) == NULL){
err(1, "strdup");
}
}
else{
rc = -1;
}
free(optdup);
if(rc < 0){
errx(1, "invalid argument: %s", option);
}
}
/**
* Initialize and set the default options in the mailx context.
*
* See description of -S argument in main for more details.
*
* @param[in] mailx The mailx content to initialize.
*/
static void
mailx_init_default_values(struct mailx *const mailx){
memset(mailx, 0, sizeof(*mailx));
mailx->subject = "";
mailx->connection_security = SMTP_SECURITY_NONE;
mailx->auth_method = SMTP_AUTH_NONE;
}
/**
* Frees the allocated memory associated with the mailx context.
*
* @param[in] mailx The mailx context to free.
*/
static void
mailx_free(const struct mailx *const mailx){
free(mailx->body);
free(mailx->server);
free(mailx->port);
free(mailx->user);
free(mailx->pass);
free(mailx->from);
}
/**
* Main program entry point for the mailx utility.
*
* This program supports the following options:
* - -a 'name:path' - Attach a file with name to display to recipient and
* file path pointing to file location on local storage.
* - -s subject - Email subject line.
* - -S key=value - A key/value pair to set various configuration options,
* controlling the behavior of the SMTP client connection.
*
* The following list contains possible options for the -S argument:
* - smtp-security - none, tls, starttls
* - smtp-auth - none, plain, login, cram-md5
* - smtp-flag - debug, no-cert-verify
* - smtp-server - server name or IP address
* - smtp-port - server port number
* - smtp-user - server authentication user name
* - smtp-pass - server authentication user password
* - smtp-from - from email account
*
* The following list shows the default option for -S argument if not provided:
* - smtp-security - none
* - smtp-auth - none
* - smtp-flag - none
* - smtp-server - localhost
* - smtp-port - 25
* - smtp-user - none
* - smtp-pass - none
* - smtp-from - none
*
* @param[in] argc Number of arguments in @p argv.
* @param[in] argv String array containing the program name and any optional
* parameters described above.
* @retval 0 Email has been sent.
* @retval 1 An error occurred while sending email. Although unlikely, an email
* can still get sent even after returning with this error code.
*/
int main(int argc, char *argv[]){
int rc;
int i;
struct mailx mailx;
mailx_init_default_values(&mailx);
while((rc = getopt(argc, argv, "a:s:S:")) != -1){
switch(rc){
case 'a':
mailx_append_attachment_arg(&mailx, optarg);
break;
case 's':
mailx.subject = optarg;
break;
case 'S':
mailx_parse_smtp_option(&mailx, optarg);
break;
default:
return 1;
}
}
argc -= optind;
argv += optind;
if(argc < 1){
errx(1, "must provide at least one email destination address");
}
if(mailx.from == NULL){
errx(1, "must provide a FROM address");
}
if(mailx.server == NULL){
if((mailx.server = strdup("localhost")) == NULL){
err(1, "strdup");
}
}
if(mailx.port == NULL){
if((mailx.port = strdup("25")) == NULL){
err(1, "strdup");
}
}
puts("Reading email body from stdin");
if((mailx.body = smtp_ffile_get_contents(stdin, NULL)) == NULL){
err(1, "failed to read email body from stdin");
}
mailx_address_append(&mailx, SMTP_ADDRESS_FROM, mailx.from);
for(i = 0; i < argc; i++){
mailx_address_append(&mailx, SMTP_ADDRESS_TO, argv[i]);
}
mailx_send(&mailx);
mailx_free(&mailx);
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,635 @@
/**
* @file
* @brief SMTP client library.
* @author James Humphrey (mail@somnisoft.com)
* @version 1.00
*
* This SMTP client library allows the user to send emails to an SMTP server.
* The user can include custom headers and MIME attachments.
*
* This software has been placed into the public domain using CC0.
*/
#ifndef SMTP_H
#define SMTP_H
#include <sys/types.h>
#include <stddef.h>
#include <stdio.h>
#ifndef SIZE_MAX
/**
* Maximum value of size_t type.
*/
# define SIZE_MAX ((size_t)(-1))
#endif /* SIZE_MAX */
/**
* Status codes indicating success or failure from calling any of the
* SMTP library functions.
*
* This code gets returned by all functions in this header.
*/
enum smtp_status_code{
/**
* Successful operation completed.
*/
SMTP_STATUS_OK = 0,
/**
* Memory allocation failed.
*/
SMTP_STATUS_NOMEM = 1,
/**
* Failed to connect to the mail server.
*/
SMTP_STATUS_CONNECT = 2,
/**
* Failed to handshake or negotiate a TLS connection with the server.
*/
SMTP_STATUS_HANDSHAKE = 3,
/**
* Failed to authenticate with the given credentials.
*/
SMTP_STATUS_AUTH = 4,
/**
* Failed to send bytes to the server.
*/
SMTP_STATUS_SEND = 5,
/**
* Failed to receive bytes from the server.
*/
SMTP_STATUS_RECV = 6,
/**
* Failed to properly close a connection.
*/
SMTP_STATUS_CLOSE = 7,
/**
* SMTP server sent back an unexpected status code.
*/
SMTP_STATUS_SERVER_RESPONSE = 8,
/**
* Invalid parameter.
*/
SMTP_STATUS_PARAM = 9,
/**
* Failed to open or read a local file.
*/
SMTP_STATUS_FILE = 10,
/**
* Failed to get the local date and time.
*/
SMTP_STATUS_DATE = 11,
/**
* Indicates the last status code in the enumeration, useful for
* bounds checking.
*
* Not a valid status code.
*/
SMTP_STATUS__LAST
};
/**
* Address source and destination types.
*/
enum smtp_address_type{
/**
* From address.
*/
SMTP_ADDRESS_FROM = 0,
/**
* To address.
*/
SMTP_ADDRESS_TO = 1,
/**
* Copy address.
*/
SMTP_ADDRESS_CC = 2,
/**
* Blind copy address.
*
* Recipients should not see any of the BCC addresses when they receive
* their email. However, some SMTP server implementations may copy this
* information into the mail header, so do not assume that this will
* always get hidden. If the BCC addresses must not get shown to the
* receivers, then send one separate email to each BCC party and add
* the TO and CC addresses manually as a header property using
* @ref smtp_header_add instead of as an address using
* @ref smtp_address_add.
*/
SMTP_ADDRESS_BCC = 3
};
/**
* Connect to the SMTP server using either an unencrypted socket or
* TLS encryption.
*/
enum smtp_connection_security{
#ifdef SMTP_OPENSSL
/**
* First connect without encryption, then negotiate an encrypted connection
* by issuing a STARTTLS command.
*
* Typically used when connecting to a mail server on port 25 or 587.
*/
SMTP_SECURITY_STARTTLS = 0,
/**
* Use TLS when initially connecting to server.
*
* Typically used when connecting to a mail server on port 465.
*/
SMTP_SECURITY_TLS = 1,
#endif /* SMTP_OPENSSL */
/**
* Do not use TLS encryption.
*
* Not recommended unless connecting to the SMTP server locally.
*/
SMTP_SECURITY_NONE = 2
};
/**
* List of supported methods for authenticating a mail user account on
* the server.
*/
enum smtp_authentication_method{
#ifdef SMTP_OPENSSL
/**
* Use HMAC-MD5.
*/
SMTP_AUTH_CRAM_MD5 = 0,
#endif /* SMTP_OPENSSL */
/**
* No authentication required.
*
* Some servers support this option if connecting locally.
*/
SMTP_AUTH_NONE = 1,
/**
* Authenticate using base64 user and password.
*/
SMTP_AUTH_PLAIN = 2,
/**
* Another base64 authentication method, similar to SMTP_AUTH_PLAIN.
*/
SMTP_AUTH_LOGIN = 3
};
/**
* Special flags defining certain behaviors for the SMTP client context.
*/
enum smtp_flag{
/**
* Print client and server communication on stderr.
*/
SMTP_DEBUG = 1 << 0,
/**
* Do not verify TLS certificate.
*
* By default, the TLS handshake function will check if a certificate
* has expired or if using a self-signed certificate. Either of those
* conditions will cause the connection to fail. This option allows the
* connection to proceed even if those checks fail.
*/
SMTP_NO_CERT_VERIFY = 1 << 1
};
struct smtp;
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/**
* Open a connection to an SMTP server and return the context.
*
* After successfully connecting and performing a handshake with the
* SMTP server, this will return a valid SMTP client context that
* the application can use in the other library functions.
*
* This always returns a valid SMTP client context even if
* the server connection or memory allocation fails. In this scenario, the
* error status will continue to propagate to future library calls for
* the SMTP context while in this failure mode.
*
* This function will ignore the SIGPIPE signal. Applications that require a
* handler for that signal should set it up after calling this function.
*
* @param[in] server Server name or IP address.
* @param[in] port Server port number.
* @param[in] connection_security See @ref smtp_connection_security.
* @param[in] flags See @ref smtp_flag.
* @param[in] cafile Path to certificate file, or NULL to use
* certificates in the default path.
* @param[out] smtp Pointer to a new SMTP context. When
* finished, the caller must free this
* context using @ref smtp_close.
* @return See @ref smtp_status_code.
*/
enum smtp_status_code
smtp_open(const char *const server,
const char *const port,
enum smtp_connection_security connection_security,
enum smtp_flag flags,
const char *const cafile,
struct smtp **smtp);
/**
* Authenticate the user using one of the methods listed in
* @ref smtp_authentication_method.
*
* @param[in] smtp SMTP client context.
* @param[in] auth_method See @ref smtp_authentication_method.
* @param[in] user SMTP user name.
* @param[in] pass SMTP password.
* @return See @ref smtp_status_code.
*/
enum smtp_status_code
smtp_auth(struct smtp *const smtp,
enum smtp_authentication_method auth_method,
const char *const user,
const char *const pass);
/**
* Sends an email using the addresses, attachments, and headers defined
* in the current SMTP context.
*
* The caller must call the @ref smtp_open function prior to this.
*
* The 'Date' header will automatically get generated here if it hasn't
* already been set using @ref smtp_header_add.
*
* If the application overrides the default 'Content-Type' header, then
* this function will output the @p body as raw data just below the email
* headers, and it will not output the attachments added using the
* smtp_attachment_add_* functions. In other words, the application must
* create its own MIME sections (if needed) when overriding the
* 'Content-Type' header.
*
* @param[in] smtp SMTP client context.
* @param[in] body Null-terminated string to send in the email body.
* @return See @ref smtp_status_code.
*/
enum smtp_status_code
smtp_mail(struct smtp *const smtp,
const char *const body);
/**
* Close the SMTP connection and frees all resources held by the
* SMTP context.
*
* @param[in] smtp SMTP client context.
* @return See @ref smtp_status_code.
*/
enum smtp_status_code
smtp_close(struct smtp *smtp);
/**
* Get the current status/error code.
*
* @param[in] smtp SMTP client context.
* @return See @ref smtp_status_code.
*/
enum smtp_status_code
smtp_status_code_get(const struct smtp *const smtp);
/**
* Clear the current error code set in the SMTP client context.
*
* @param[in,out] smtp SMTP client context.
* @return Previous error code before clearing.
*/
enum smtp_status_code
smtp_status_code_clear(struct smtp *const smtp);
/**
* Set the error status of the SMTP client context and return the same code.
*
* This allows the caller to clear an error status to SMTP_STATUS_OK
* so that previous errors will stop propagating. However, this will only
* work correctly for clearing the SMTP_STATUS_PARAM and SMTP_STATUS_FILE
* errors. Do not use this to clear any other error codes.
*
* @deprecated Use @ref smtp_status_code_clear instead.
*
* @param[in] smtp SMTP client context.
* @param[in] new_status_code See @ref smtp_status_code.
* @return See @ref smtp_status_code.
*/
enum smtp_status_code
smtp_status_code_set(struct smtp *const smtp,
enum smtp_status_code new_status_code);
/**
* Convert a standard SMTP client status code to a descriptive string.
*
* @param[in] status_code Status code returned from one of the other
* library functions.
* @return String containing a description of the @p status_code. The caller
* must not free or modify this string.
*/
const char *
smtp_status_code_errstr(enum smtp_status_code status_code);
/**
* Add a key/value header to the header list in the SMTP context.
*
* If adding a header with an existing key, this will insert instead of
* replacing the existing header. See @ref smtp_header_clear_all.
*
* See @ref smtp_mail when overriding the default 'Content-Type' header.
*
* @param[in] smtp SMTP client context.
* @param[in] key Key name for new header. It must consist only of
* printable US-ASCII characters except colon.
* @param[in] value Value for new header. It must consist only of printable
* US-ASCII, space, or horizontal tab. If set to NULL,
* this will prevent the header from printing out.
* @return See @ref smtp_status_code.
*/
enum smtp_status_code
smtp_header_add(struct smtp *const smtp,
const char *const key,
const char *const value);
/**
* Free all memory related to email headers.
*
* @param[in] smtp SMTP client context.
*/
void
smtp_header_clear_all(struct smtp *const smtp);
/**
* Add a FROM, TO, CC, or BCC address destination to this SMTP context.
*
* @note Some SMTP servers may reject over 100 recipients.
*
* @param[in] smtp SMTP client context.
* @param[in] type See @ref smtp_address_type.
* @param[in] email The email address of the party. Must consist only of
* printable characters excluding the angle brackets
* (<) and (>).
* @param[in] name Name or description of the party. Must consist only of
* printable characters, excluding the quote characters. If
* set to NULL or empty string, no name will get associated
* with this email.
* @return See @ref smtp_status_code.
*/
enum smtp_status_code
smtp_address_add(struct smtp *const smtp,
enum smtp_address_type type,
const char *const email,
const char *const name);
/**
* Free all memory related to the address list.
*
* @param[in] smtp SMTP client context.
*/
void
smtp_address_clear_all(struct smtp *const smtp);
/**
* Add a file attachment from a path.
*
* See @ref smtp_attachment_add_mem for more details.
*
* @param[in] smtp SMTP client context.
* @param[in] name Filename of the attachment shown to recipients. Must
* consist only of printable ASCII characters, excluding
* the quote characters (') and (").
* @param[in] path Path to file.
* @return See @ref smtp_status_code.
*/
enum smtp_status_code
smtp_attachment_add_path(struct smtp *const smtp,
const char *const name,
const char *const path);
/**
* Add an attachment using a file pointer.
*
* See @ref smtp_attachment_add_mem for more details.
*
* @param[in] smtp SMTP client context.
* @param[in] name Filename of the attachment shown to recipients. Must
* consist only of printable ASCII characters, excluding
* the quote characters (') and (").
* @param[in] fp File pointer already opened by the caller.
* @return See @ref smtp_status_code.
*/
enum smtp_status_code
smtp_attachment_add_fp(struct smtp *const smtp,
const char *const name,
FILE *fp);
/**
* Add a MIME attachment to this SMTP context with the data retrieved
* from memory.
*
* The attachment data will get base64 encoded before sending to the server.
*
* @param[in] smtp SMTP client context.
* @param[in] name Filename of the attachment shown to recipients. Must
* consist only of printable ASCII characters, excluding
* the quote characters (') and (").
* @param[in] data Raw attachment data stored in memory.
* @param[in] datasz Number of bytes in @p data, or -1 if data
* null-terminated.
* @return See @ref smtp_status_code.
*/
enum smtp_status_code
smtp_attachment_add_mem(struct smtp *const smtp,
const char *const name,
const void *const data,
size_t datasz);
/**
* Remove all attachments from the SMTP client context.
*
* @param[in] smtp SMTP client context.
*/
void
smtp_attachment_clear_all(struct smtp *const smtp);
/*
* The SMTP_INTERNAL DEFINE section contains definitions that get used
* internally by the SMTP client library.
*/
#ifdef SMTP_INTERNAL_DEFINE
/**
* SMTP codes returned by the server and parsed by the client.
*/
enum smtp_result_code{
/**
* Client error code which does not get set by the server.
*/
SMTP_INTERNAL_ERROR = -1,
/**
* Returned when ready to begin processing next step.
*/
SMTP_READY = 220,
/**
* Returned in response to QUIT.
*/
SMTP_CLOSE = 221,
/**
* Returned if client successfully authenticates.
*/
SMTP_AUTH_SUCCESS = 235,
/**
* Returned when some commands successfully complete.
*/
SMTP_DONE = 250,
/**
* Returned for some multi-line authentication mechanisms where this code
* indicates the next stage in the authentication step.
*/
SMTP_AUTH_CONTINUE = 334,
/**
* Returned in response to DATA command.
*/
SMTP_BEGIN_MAIL = 354
};
/**
* Used for parsing out the responses from the SMTP server.
*
* For example, if the server sends back '250-STARTTLS', then code would
* get set to 250, more would get set to 1, and text would get set to STARTTLS.
*/
struct smtp_command{
/**
* Result code converted to an integer.
*/
enum smtp_result_code code;
/**
* Indicates if more server commands follow.
*
* This will get set to 1 if the fourth character in the response line
* contains a '-', otherwise this will get set to 0.
*/
int more;
/**
* The text shown after the status code.
*/
const char *text;
};
/**
* Return codes for the getdelim interface which allows the caller to check
* if more delimited lines can get processed.
*/
enum str_getdelim_retcode{
/**
* An error occurred during the getdelim processing.
*/
STRING_GETDELIMFD_ERROR = -1,
/**
* Found a new line and can process more lines in the next call.
*/
STRING_GETDELIMFD_NEXT = 0,
/**
* Found a new line and unable to read any more lines at this time.
*/
STRING_GETDELIMFD_DONE = 1
};
/**
* Data structure for read buffer and line parsing.
*
* This assists with getting and parsing the server response lines.
*/
struct str_getdelimfd{
/**
* Read buffer which may include bytes past the delimiter.
*/
char *_buf;
/**
* Number of allocated bytes in the read buffer.
*/
size_t _bufsz;
/**
* Number of actual stored bytes in the read buffer.
*/
size_t _buf_len;
/**
* Current line containing the text up to the delimiter.
*/
char *line;
/**
* Number of stored bytes in the line buffer.
*/
size_t line_len;
/**
* Function pointer to a custom read function for the
* @ref smtp_str_getdelimfd interface.
*
* This function prototype has similar semantics to the read function.
* The @p gdfd parameter allows the custom function to pull the user_data
* info from the @ref str_getdelimfd struct which can contain file pointer,
* socket connection, etc.
*/
long (*getdelimfd_read)(struct str_getdelimfd *const gdfd,
void *buf,
size_t count);
/**
* User data which gets sent to the read handler function.
*/
void *user_data;
/**
* Character delimiter used for determining line separation.
*/
int delim;
/**
* Padding structure to align.
*/
char pad[4];
};
#endif /* SMTP_INTERNAL_DEFINE */
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* SMTP_H */

View File

@@ -0,0 +1,62 @@
#include <stdio.h>
#include "smtp.h"
#define MAIL_SERVER "localhost"
#define MAIL_PORT "587"
#define MAIL_CONNECTION_SECURITY SMTP_SECURITY_NONE
#define MAIL_FLAGS SMTP_DEBUG
#define MAIL_CAFILE NULL
#define MAIL_AUTH SMTP_AUTH_NONE
#define MAIL_USER "mail@somnisoft.com"
#define MAIL_PASS "password"
#define MAIL_FROM "mail@somnisoft.com"
#define MAIL_FROM_NAME "From Name"
#define MAIL_SUBJECT "Subject Line"
#define MAIL_TO "mail@somnisoft.com"
#define MAIL_TO_NAME "To Name"
int main(void){
struct smtp *smtp;
enum smtp_status_code rc;
const char *const email_body =
"<html>\n"
" <head><title>HTML Email</title></head>\n"
" <body>\n"
" <h1>H1</h1>\n"
" <h2>H2</h1>\n"
" <h3>H3</h1>\n"
" <h4>H4</h1>\n"
" <h5>H5</h1>\n"
" <h6>H6</h1>\n"
" </body>\n"
"</html>\n";
smtp_open(MAIL_SERVER,
MAIL_PORT,
MAIL_CONNECTION_SECURITY,
MAIL_FLAGS,
MAIL_CAFILE,
&smtp);
smtp_auth(smtp,
MAIL_AUTH,
MAIL_USER,
MAIL_PASS);
smtp_address_add(smtp,
SMTP_ADDRESS_FROM,
MAIL_FROM,
MAIL_FROM_NAME);
smtp_address_add(smtp,
SMTP_ADDRESS_TO,
MAIL_TO,
MAIL_TO_NAME);
smtp_header_add(smtp,
"Subject",
MAIL_SUBJECT);
smtp_header_add(smtp,
"Content-Type",
"text/html");
smtp_mail(smtp, email_body);
rc = smtp_close(smtp);
if(rc != SMTP_STATUS_OK){
fprintf(stderr, "smtp failed: %s\n", smtp_status_code_errstr(rc));
return 1;
}
return 0;
}

View File

@@ -0,0 +1,55 @@
#include <stdio.h>
#include "smtp.h"
#define MAIL_SERVER "mail.example.com"
#define MAIL_PORT "587"
#define MAIL_CONNECTION_SECURITY SMTP_SECURITY_STARTTLS
#define MAIL_FLAGS (SMTP_DEBUG | \
SMTP_NO_CERT_VERIFY) /* Do not verify cert. */
#define MAIL_CAFILE NULL
#define MAIL_AUTH SMTP_AUTH_PLAIN
#define MAIL_USER "mail@example.com"
#define MAIL_PASS "password"
#define MAIL_FROM "mail@example.com"
#define MAIL_FROM_NAME "From Name"
#define MAIL_SUBJECT "Subject Line"
#define MAIL_BODY "Email Body"
#define MAIL_TO "to@example.com"
#define MAIL_TO_NAME "To Name"
int main(void)
{
struct smtp *smtp;
int rc;
rc = smtp_open(MAIL_SERVER,
MAIL_PORT,
MAIL_CONNECTION_SECURITY,
MAIL_FLAGS,
MAIL_CAFILE,
&smtp);
rc = smtp_auth(smtp,
MAIL_AUTH,
MAIL_USER,
MAIL_PASS);
rc = smtp_address_add(smtp,
SMTP_ADDRESS_FROM,
MAIL_FROM,
MAIL_FROM_NAME);
rc = smtp_address_add(smtp,
SMTP_ADDRESS_TO,
MAIL_TO,
MAIL_TO_NAME);
rc = smtp_header_add(smtp,
"Subject",
MAIL_SUBJECT);
rc = smtp_attachment_add_mem(smtp,
"test.txt",
"Test email attachment.",
-1);
rc = smtp_mail(smtp,
MAIL_BODY);
rc = smtp_close(smtp);
if(rc != SMTP_STATUS_OK){
fprintf(stderr, "smtp failed: %s\n", smtp_status_code_errstr(rc));
return 1;
}
return 0;
}

View File

@@ -0,0 +1,819 @@
/**
* @file
* @brief Test seams for the smtp-client library.
* @author James Humphrey (mail@somnisoft.com)
* @version 1.00
*
* Used by the smtp-client testing framework to inject specific return values
* by some standard library functions. This makes it possible to test less
* common errors like out of memory conditions and input/output errors.
*
* This software has been placed into the public domain using CC0.
*/
#include <assert.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "test.h"
/**
* See @ref g_smtp_test_err_bio_new_socket_ctr and
* @ref test_seams_countdown_global.
*/
int g_smtp_test_err_bio_new_socket_ctr = -1;
/**
* See @ref g_smtp_test_err_bio_should_retry_ctr and
* @ref test_seams_countdown_global.
*/
int g_smtp_test_err_bio_should_retry_ctr = -1;
/**
* See @ref g_smtp_test_err_bio_should_retry_rc.
*/
int g_smtp_test_err_bio_should_retry_rc = -1;
/**
* See @ref g_smtp_test_err_calloc_ctr and @ref test_seams_countdown_global.
*/
int g_smtp_test_err_calloc_ctr = -1;
/**
* See @ref g_smtp_test_err_close_ctr and @ref test_seams_countdown_global.
*/
int g_smtp_test_err_close_ctr = -1;
/**
* See @ref g_smtp_test_err_connect_ctr and @ref test_seams_countdown_global.
*/
int g_smtp_test_err_connect_ctr = -1;
/**
* See @ref g_smtp_test_err_err_peek_error_ctr and
* @ref test_seams_countdown_global.
*/
int g_smtp_test_err_err_peek_error_ctr = -1;
/**
* See @ref g_smtp_test_err_fclose_ctr and @ref test_seams_countdown_global.
*/
int g_smtp_test_err_fclose_ctr = -1;
/**
* See @ref g_smtp_test_err_ferror_ctr and @ref test_seams_countdown_global.
*/
int g_smtp_test_err_ferror_ctr = -1;
/**
* See @ref g_smtp_test_err_gmtime_r_ctr @ref test_seams_countdown_global.
*/
int g_smtp_test_err_gmtime_r_ctr = -1;
/**
* See @ref g_smtp_test_err_hmac_ctr @ref test_seams_countdown_global.
*/
int g_smtp_test_err_hmac_ctr = -1;
/**
* See @ref g_smtp_test_err_localtime_r_ctr and
* @ref test_seams_countdown_global.
*/
int g_smtp_test_err_localtime_r_ctr = -1;
/**
* See @ref g_smtp_test_err_malloc_ctr and @ref test_seams_countdown_global.
*/
int g_smtp_test_err_malloc_ctr = -1;
/**
* See @ref g_smtp_test_err_mktime_ctr and @ref test_seams_countdown_global.
*/
int g_smtp_test_err_mktime_ctr = -1;
/**
* See @ref g_smtp_test_err_realloc_ctr and @ref test_seams_countdown_global.
*/
int g_smtp_test_err_realloc_ctr = -1;
/**
* See @ref g_smtp_test_err_recv_ctr and @ref test_seams_countdown_global.
*/
int g_smtp_test_err_recv_ctr = -1;
/**
* See @ref g_smtp_test_err_recv_rc.
*/
int g_smtp_test_err_recv_rc = -1;
/**
* See @ref g_smtp_test_err_recv_bytes and @ref test_seams_countdown_global.
*/
char g_smtp_test_err_recv_bytes[90] = {0};
/**
* See @ref g_smtp_test_err_select_ctr and @ref test_seams_countdown_global.
*/
int g_smtp_test_err_select_ctr = -1;
/**
* See @ref g_smtp_test_err_send_ctr and @ref test_seams_countdown_global.
*/
int g_smtp_test_err_send_ctr = -1;
/**
* See @ref g_smtp_test_send_one_byte.
*/
int g_smtp_test_send_one_byte = 0;
/**
* See @ref g_smtp_test_err_si_add_size_t_ctr
* and @ref test_seams_countdown_global.
*/
int g_smtp_test_err_si_add_size_t_ctr = -1;
/**
* See @ref g_smtp_test_err_si_sub_size_t_ctr
* and @ref test_seams_countdown_global.
*/
int g_smtp_test_err_si_sub_size_t_ctr = -1;
/**
* See @ref g_smtp_test_err_si_mul_size_t_ctr
* and @ref test_seams_countdown_global.
*/
int g_smtp_test_err_si_mul_size_t_ctr = -1;
/**
* See @ref g_smtp_test_err_socket_ctr and @ref test_seams_countdown_global.
*/
int g_smtp_test_err_socket_ctr = -1;
/**
* See @ref g_smtp_test_err_ssl_connect_ctr and
* @ref test_seams_countdown_global.
*/
int g_smtp_test_err_ssl_connect_ctr = -1;
/**
* See @ref g_smtp_test_err_ssl_ctx_new_ctr and
* @ref test_seams_countdown_global.
*/
int g_smtp_test_err_ssl_ctx_new_ctr = -1;
/**
* See @ref g_smtp_test_err_ssl_do_handshake_ctr and
* @ref test_seams_countdown_global.
*/
int g_smtp_test_err_ssl_do_handshake_ctr = -1;
/**
* See @ref g_smtp_test_err_ssl_get_peer_certificate_ctr and
* @ref test_seams_countdown_global.
*/
int g_smtp_test_err_ssl_get_peer_certificate_ctr = -1;
/**
* See @ref g_smtp_test_err_x509_check_host_ctr and
* @ref test_seams_countdown_global.
*/
int g_smtp_test_err_x509_check_host_ctr = -1;
/**
* See @ref g_smtp_test_err_ssl_new_ctr and @ref test_seams_countdown_global.
*/
int g_smtp_test_err_ssl_new_ctr = -1;
/**
* See @ref g_smtp_test_err_ssl_read_ctr and @ref test_seams_countdown_global.
*/
int g_smtp_test_err_ssl_read_ctr = -1;
/**
* See @ref g_smtp_test_err_ssl_write_ctr and @ref test_seams_countdown_global.
*/
int g_smtp_test_err_ssl_write_ctr = -1;
/**
* See @ref g_smtp_test_err_sprintf_ctr and @ref test_seams_countdown_global.
*/
int g_smtp_test_err_sprintf_ctr = -1;
/**
* See @ref g_smtp_test_err_sprintf_rc.
*/
int g_smtp_test_err_sprintf_rc = 0;
/**
* See @ref g_smtp_test_strlen_custom_ret.
*/
int g_smtp_test_strlen_custom_ret = 0;
/**
* See @ref g_smtp_test_strlen_ret_value.
*/
size_t g_smtp_test_strlen_ret_value = 0;
/**
* See @ref g_smtp_test_time_custom_ret.
*/
int g_smtp_test_time_custom_ret = 0;
/**
* See @ref g_smtp_test_time_ret_value.
*/
time_t g_smtp_test_time_ret_value = 0;
/**
* Decrement an error counter until it reaches -1.
*
* Once a counter reaches -1, it will return a successful response (1). This
* typically gets used to denote when to cause a function to fail. For example,
* the unit test or functional test might need to cause the realloc() function
* to fail after calling it the third time.
*
* @param[in,out] test_err_ctr Integer counter to decrement.
* @retval 0 The counter has been decremented, but did not reach -1 yet.
* @retval 1 The counter has reached -1.
*/
int
smtp_test_seam_dec_err_ctr(int *const test_err_ctr){
if(*test_err_ctr >= 0){
*test_err_ctr -= 1;
if(*test_err_ctr < 0){
return 1;
}
}
return 0;
}
/**
* Allows the test harness to control when BIO_new_socket() fails.
*
* @param[in] sock Existing socket to attach the BIO to.
* @param[in] close_flag Close flag for new BIO.
* @retval BIO* New BIO created on existing socket.
* @retval NULL Failed to create the new BIO.
*/
BIO *
smtp_test_seam_bio_new_socket(int sock,
int close_flag){
if(smtp_test_seam_dec_err_ctr(&g_smtp_test_err_bio_new_socket_ctr)){
return NULL;
}
return BIO_new_socket(sock, close_flag);
}
/**
* Allows the test harness to control when BIO_should_retry() fails.
*
* @param[in] bio Existing BIO connection.
* @retval 0 The error condition does not allow a retry.
* @retval 1 The error condition allows a retry.
*/
int
smtp_test_seam_bio_should_retry(BIO *bio){
if(smtp_test_seam_dec_err_ctr(&g_smtp_test_err_bio_should_retry_ctr)){
return 0;
}
if(g_smtp_test_err_bio_should_retry_rc != -1){
return g_smtp_test_err_bio_should_retry_rc;
}
return BIO_should_retry(bio);
}
/**
* Allows the test harness to control when calloc() fails.
*
* @param[in] nelem Number of elements to allocate.
* @param[in] elsize Size of each element to allocate.
* @retval void* Pointer to new allocated memory.
* @retval NULL Memory allocation failed.
*/
void *
smtp_test_seam_calloc(size_t nelem,
size_t elsize){
if(smtp_test_seam_dec_err_ctr(&g_smtp_test_err_calloc_ctr)){
errno = ENOMEM;
return NULL;
}
return calloc(nelem, elsize);
}
/**
* Allows the test harness to control when close() fails.
*
* @param[in] fildes Socket file descriptor to close.
* @retval 0 Successfully closed file descriptor.
* @retval -1 Failed to close file descriptor.
*/
int
smtp_test_seam_close(int fildes){
if(smtp_test_seam_dec_err_ctr(&g_smtp_test_err_close_ctr)){
errno = EBADF;
return -1;
}
return close(fildes);
}
/**
* Allows the test harness to control when connect() fails.
*
* @param[in] socket Socket connection.
* @param[in] address Network address of peer.
* @param[in] address_len Number of bytes in @p address.
* @retval 0 Successfully connected to the peer.
* @retval -1 Failed to connect to the peer.
*/
int
smtp_test_seam_connect(int socket,
const struct sockaddr *address,
socklen_t address_len){
if(smtp_test_seam_dec_err_ctr(&g_smtp_test_err_connect_ctr)){
errno = ECONNREFUSED;
return -1;
}
return connect(socket, address, address_len);
}
/**
* Allows the test harness to control when ERR_peek_error() returns a failure
* code.
*
* @retval 0 No error code on the error queue.
* @retval !0 An error code exists on the error queue.
*/
unsigned long
smtp_test_seam_err_peek_error(void){
if(smtp_test_seam_dec_err_ctr(&g_smtp_test_err_err_peek_error_ctr)){
return 1;
}
return ERR_peek_error();
}
/**
* Allows the test harness to control when fclose() fails.
*
* @param[in] stream File stream to close.
* @retval 0 Successfully closed the file stream.
* @retval EOF An error occurred while closing the file stream.
*/
int smtp_test_seam_fclose(FILE *stream){
if(smtp_test_seam_dec_err_ctr(&g_smtp_test_err_fclose_ctr)){
errno = EBADF;
return EOF;
}
return fclose(stream);
}
/**
* Allows the test harness to control the file stream error indicator return
* value in ferror().
*
* @param[in] stream Check for errors on this file stream.
* @retval 0 No errors detected on the file stream.
* @retval 1 An error occurred during a file stream operation.
*/
int
smtp_test_seam_ferror(FILE *stream){
if(smtp_test_seam_dec_err_ctr(&g_smtp_test_err_ferror_ctr)){
return 1;
}
return ferror(stream);
}
/**
* Allows the test harness to control when gmtime_r() fails.
*
* @param[in] timep Time value to convert to a struct tm.
* @param[out] result Converts the @p timep value into a UTC tm structure
* value and stores the results in this pointer.
* @retval tm* time_t value converted to a tm structure value.
* @retval NULL An error occurred while converting the time.
*/
struct tm *
smtp_test_seam_gmtime_r(const time_t *timep,
struct tm *result){
if(smtp_test_seam_dec_err_ctr(&g_smtp_test_err_gmtime_r_ctr)){
return NULL;
}
return gmtime_r(timep, result);
}
/**
* Allows the test harness to control when HMAC() fails.
*
* @param[in] evp_md Hash function.
* @param[in] key Hash key.
* @param[in] key_len Number of bytes in @p key.
* @param[in] d Message data.
* @param[in] n Number of bytes in @p d.
* @param[out] md The computed message authentication code.
* @param[in] md_len Number of bytes in @p md.
* @retval uchar* Pointer to @p md.
* @retval NULL An error occurred.
*/
unsigned char *
smtp_test_seam_hmac(const EVP_MD *evp_md,
const void *key,
int key_len,
const unsigned char *d,
size_t n,
unsigned char *md,
unsigned int *md_len){
if(smtp_test_seam_dec_err_ctr(&g_smtp_test_err_hmac_ctr)){
return NULL;
}
return HMAC(evp_md, key, key_len, d, n, md, md_len);
}
/**
* Allows the test harness to control when localtime_r() fails.
*
* @param[in] timep Time value to convert to a struct tm.
* @param[out] result Converts the @p timep value into a local time tm
* structure value and stores the results in this pointer.
* @retval tm* time_t value converted to a tm structure value.
* @retval NULL An error occurred while converting the time.
*/
struct tm *
smtp_test_seam_localtime_r(const time_t *timep,
struct tm *result){
if(smtp_test_seam_dec_err_ctr(&g_smtp_test_err_localtime_r_ctr)){
return NULL;
}
return localtime_r(timep, result);
}
/**
* Allows the test harness to control when malloc() fails.
*
* @param[in] size Number of bytes to allocate.
* @retval void* Pointer to new allocated memory.
* @retval NULL Memory allocation failed.
*/
void *
smtp_test_seam_malloc(size_t size){
if(smtp_test_seam_dec_err_ctr(&g_smtp_test_err_malloc_ctr)){
errno = ENOMEM;
return NULL;
}
return malloc(size);
}
/**
* Allows the test harness to control when mktime() fails.
*
* @param[in] timeptr tm data structure to convert to time_t.
* @retval >=0 Time since the epoch.
* @retval -1 Failed to convert the time.
*/
time_t
smtp_test_seam_mktime(struct tm *timeptr){
if(smtp_test_seam_dec_err_ctr(&g_smtp_test_err_mktime_ctr)){
return -1;
}
return mktime(timeptr);
}
/**
* Allows the test harness to control when realloc() fails.
*
* @param[in] ptr Previously allocated memory or NULL memory has not been
* allocated yet.
* @param[in] size Number of bytes to reallocate.
* @retval void* Pointer to new allocated memory.
* @retval NULL Memory allocation failed.
*/
void *
smtp_test_seam_realloc(void *ptr,
size_t size){
if(smtp_test_seam_dec_err_ctr(&g_smtp_test_err_realloc_ctr)){
errno = ENOMEM;
return NULL;
}
return realloc(ptr, size);
}
/**
* Allows the test harness to control when recv() fails.
*
* @param[in] socket TCP network socket.
* @param[in] buffer Store received data in this buffer.
* @param[in] length Number of bytes in @p buffer.
* @param[in] flags Set this to 0.
* @retval >=0 Number of bytes received.
* @retval -1 Failed to receive bytes over the network.
*/
long
smtp_test_seam_recv(int socket,
void *buffer,
size_t length,
int flags){
size_t bytes_inject_len;
if(smtp_test_seam_dec_err_ctr(&g_smtp_test_err_recv_ctr)){
if(g_smtp_test_err_recv_rc != -1){
return g_smtp_test_err_recv_rc;
}
if(*g_smtp_test_err_recv_bytes){
bytes_inject_len = strlen(g_smtp_test_err_recv_bytes);
assert(bytes_inject_len < length && bytes_inject_len < LONG_MAX);
memcpy(buffer, g_smtp_test_err_recv_bytes, bytes_inject_len);
return (long)bytes_inject_len;
}
errno = EBADF;
return -1;
}
return recv(socket, buffer, length, flags);
}
/**
* Allows the test harness to control when select() fails.
*
* @param[in] nfds Check for file descriptors in range 0 to (@p nfds - 1)
* which have any of the read/write/error conditions.
* @param[in] readfds Checks for file descriptors in fd_set that have bytes
* ready for reading.
* @param[in] writefds Checks for file descriptors in fd_set that have bytes
* ready for writing.
* @param[in] errorfds Checks for file descriptors in fd_set that have errors
* pending.
* @param[in] timeout Wait for the read/write/error conditions in blocking
* mode until this timeout or an interrupt occurs.
* @retval >=0 Number of bits set in the bitmask.
* @retval -1 An error occurred.
*/
int
smtp_test_seam_select(int nfds,
fd_set *readfds,
fd_set *writefds,
fd_set *errorfds,
struct timeval *timeout){
if(smtp_test_seam_dec_err_ctr(&g_smtp_test_err_select_ctr)){
errno = EINTR;
return -1;
}
return select(nfds, readfds, writefds, errorfds, timeout);
}
/**
* Allows the test harness to control when send() fails.
*
* @param[in] socket TCP network socket.
* @param[in] buffer Data to send over the network.
* @param[in] length Number of bytes in @p buffer.
* @param[in] flags Set this to 0.
* @retval >=0 Number of bytes sent.
* @retval -1 Failed to send bytes over the network.
*/
ssize_t
smtp_test_seam_send(int socket,
const void *buffer,
size_t length,
int flags){
long sent_bytes;
size_t bytes_to_send;
if(smtp_test_seam_dec_err_ctr(&g_smtp_test_err_send_ctr)){
errno = EBADF;
sent_bytes = -1;
}
else{
bytes_to_send = length;
if(g_smtp_test_send_one_byte){
bytes_to_send = 1;
}
sent_bytes = send(socket, buffer, bytes_to_send, flags);
}
return sent_bytes;
}
/**
* Allows the test harness to control when socket() fails.
*
* @param[in] domain Socket domain.
* @param[in] type Socket type.
* @param[in] protocol Socket protocol.
* @retval !(-1) The file descriptor for the new socket.
* @retval -1 Failed to create the socket.
*/
int
smtp_test_seam_socket(int domain,
int type,
int protocol){
if(smtp_test_seam_dec_err_ctr(&g_smtp_test_err_socket_ctr)){
errno = EINVAL;
return -1;
}
return socket(domain, type, protocol);
}
/**
* Allows the test harness to control when SSL_connect() fails.
*
* @param[in] ssl OpenSSL handle.
* @retval 1 TLS connection handshake successful.
* @retval <1 TLS connection handshake failed.
*/
int
smtp_test_seam_ssl_connect(SSL *ssl){
if(smtp_test_seam_dec_err_ctr(&g_smtp_test_err_ssl_connect_ctr)){
return 0;
}
return SSL_connect(ssl);
}
/**
* Allows the test harness to control when SSL_CTX_new() fails.
*
* @param[in] method TLS connection method.
* @retval SSL_CTX* Pointer to new TLS context.
* @retval NULL Failed to create new TLS context.
*/
SSL_CTX *
smtp_test_seam_ssl_ctx_new(const SSL_METHOD *method){
if(smtp_test_seam_dec_err_ctr(&g_smtp_test_err_ssl_ctx_new_ctr)){
return NULL;
}
return SSL_CTX_new(method);
}
/**
* Allows the test harness to control when SSL_do_handshake() fails.
*
* @param[in] ssl OpenSSL handle.
* @retval 1 TLS handshake successful.
* @retval <1 TLS handshake failed.
*/
int
smtp_test_seam_ssl_do_handshake(SSL *ssl){
if(smtp_test_seam_dec_err_ctr(&g_smtp_test_err_ssl_do_handshake_ctr)){
return 0;
}
return SSL_do_handshake(ssl);
}
/**
* Allows the test harness to control when SSL_get_peer_certificate() fails.
*
* @param[in] ssl OpenSSL handle.
* @retval X509* Peer certficate which must get freed by using X509_free().
* @retval NULL Failed to get the peer certificate.
*/
X509 *
smtp_test_seam_ssl_get_peer_certificate(const SSL *ssl){
if(smtp_test_seam_dec_err_ctr(&g_smtp_test_err_ssl_get_peer_certificate_ctr)){
return NULL;
}
return SSL_get_peer_certificate(ssl);
}
/**
* Allows the test harness to control when X509_check_host() fails.
*
* @param[in] cert X509 certificate handle.
* @param[in] name Server name.
* @param[in] namelen Number of characters in @p name or 0 if null-terminated.
* @param[in] flags Usually set to 0.
* @param[in] peername Pointer to CN from certificate stored in this buffer
* if not NULL.
* @retval 1 Successful host check.
* @retval 0 Failed host check.
* @retval -1 Internal error.
*/
int
smtp_test_seam_x509_check_host(X509 *cert,
const char *name,
size_t namelen,
unsigned int flags,
char **peername){
if(smtp_test_seam_dec_err_ctr(&g_smtp_test_err_x509_check_host_ctr)){
return -1;
}
return X509_check_host(cert, name, namelen, flags, peername);
}
/**
* Allows the test harness to control when SSL_new() fails.
*
* @param[in] ctx OpenSSL TLS context.
* @retval SSL* Pointer to a new TLS context.
* @retval NULL Failed to create new TLS context.
*/
SSL *
smtp_test_seam_ssl_new(SSL_CTX *ctx){
if(smtp_test_seam_dec_err_ctr(&g_smtp_test_err_ssl_new_ctr)){
return NULL;
}
return SSL_new(ctx);
}
/**
* Allows the test harness to control when SSL_read() fails.
*
* @param[in] ssl OpenSSL TLS object.
* @param[in] buf Store received data in this buffer.
* @param[in] num Number of bytes in @p buf.
* @retval >0 Number of bytes successfully read from the TLS connection.
* @retval <=0 Failed to read bytes on the TLS connection.
*/
int
smtp_test_seam_ssl_read(SSL *ssl,
void *buf,
int num){
size_t bytes_inject_len;
if(smtp_test_seam_dec_err_ctr(&g_smtp_test_err_ssl_read_ctr)){
if(*g_smtp_test_err_recv_bytes){
bytes_inject_len = strlen(g_smtp_test_err_recv_bytes);
assert(bytes_inject_len < (size_t)num && bytes_inject_len < INT_MAX);
memcpy(buf, g_smtp_test_err_recv_bytes, bytes_inject_len);
return (int)bytes_inject_len;
}
return -1;
}
return SSL_read(ssl, buf, num);
}
/**
* Allows the test harness to control when SSL_write() fails.
*
* @param[in] ssl OpenSSL TLS object.
* @param[in] buf Data to write to the TLS connection.
* @param[in] num Number of bytes in @p buf.
* @retval >0 Number of bytes successfully written to the TLS connection.
* @retval <=0 Failed to write bytes to the TLS connection.
*/
int
smtp_test_seam_ssl_write(SSL *ssl,
const void *buf,
int num){
if(smtp_test_seam_dec_err_ctr(&g_smtp_test_err_ssl_write_ctr)){
return -1;
}
return SSL_write(ssl, buf, num);
}
/**
* Allows the test harness to control when sprintf() fails.
*
* @param[in] s Buffer to store the output contents to.
* @param[in] format Format string defined in sprintf().
* @retval >=0 Number of bytes copied to @p s, excluding the null-terminator.
* @retval <0 Output or formatting error.
*/
int
smtp_test_seam_sprintf(char *s,
const char *format, ...){
va_list ap;
int rc;
if(smtp_test_seam_dec_err_ctr(&g_smtp_test_err_sprintf_ctr)){
errno = ENOMEM;
return g_smtp_test_err_sprintf_rc;
}
va_start(ap, format);
rc = vsprintf(s, format, ap);
va_end(ap);
return rc;
}
/**
* Allows the test harness to control the return value of strlen().
*
* @param[in] s Null-terminated string.
* @return Length of @p s.
*/
size_t
smtp_test_seam_strlen(const char *s){
size_t result;
if(g_smtp_test_strlen_custom_ret){
result = g_smtp_test_strlen_ret_value;
}
else{
result = strlen(s);
}
return result;
}
/**
* Allows the test harness to control when time() fails.
*
* @param[out] tloc Buffer to hold the time_t results.
* @retval >=0 Time in seconds since the Epoch.
* @retval -1 Failed to store the time in @p tloc.
*/
time_t
smtp_test_seam_time(time_t *tloc){
if(g_smtp_test_time_custom_ret){
return g_smtp_test_time_ret_value;
}
return time(tloc);
}

View File

@@ -0,0 +1,284 @@
/**
* @file
* @brief Test seams for the smtp-client library.
* @author James Humphrey (mail@somnisoft.com)
* @version 1.00
*
* Used by the smtp-client testing framework to inject specific return values
* by some standard library functions. This makes it possible to test less
* common errors like out of memory conditions and input/output errors.
*
* This software has been placed into the public domain using CC0.
*/
#ifndef SMTP_TEST_SEAMS_H
#define SMTP_TEST_SEAMS_H
#include "test.h"
/*
* Redefine these functions to internal test seam functions.
*/
#undef BIO_new_socket
#undef BIO_should_retry
#undef calloc
#undef close
#undef connect
#undef ERR_peek_error
#undef fclose
#undef ferror
#undef gmtime_r
#undef HMAC
#undef localtime_r
#undef malloc
#undef mktime
#undef realloc
#undef recv
#undef select
#undef send
#undef socket
#undef SSL_connect
#undef SSL_CTX_new
#undef SSL_do_handshake
#undef SSL_get_peer_certificate
#undef X509_check_host
#undef SSL_new
#undef SSL_read
#undef SSL_write
#undef sprintf
#undef strlen
#undef time
/**
* Redefine this function from smtp.c and inject a test seam which
* can control when this function fails.
*
* See @ref smtp_test_seam_bio_new_socket.
*/
#define BIO_new_socket smtp_test_seam_bio_new_socket
/**
* Redefine this function from smtp.c and inject a test seam which
* can control when this function fails.
*
* See @ref smtp_test_seam_bio_should_retry.
*/
#define BIO_should_retry smtp_test_seam_bio_should_retry
/**
* Redefine this function from smtp.c and inject a test seam which
* can control when this function fails.
*
* See @ref smtp_test_seam_calloc.
*/
#define calloc smtp_test_seam_calloc
/**
* Redefine this function from smtp.c and inject a test seam which
* can control when this function fails.
*
* See @ref smtp_test_seam_close.
*/
#define close smtp_test_seam_close
/**
* Redefine this function from smtp.c and inject a test seam which
* can control when this function fails.
*
* See @ref smtp_test_seam_connect.
*/
#define connect smtp_test_seam_connect
/**
* Redefine this function from smtp.c and inject a test seam which
* can control when this function fails.
*
* See @ref smtp_test_seam_err_peek_error.
*/
#define ERR_peek_error smtp_test_seam_err_peek_error
/**
* Redefine this function from smtp.c and inject a test seam which
* can control when this function fails.
*
* See @ref smtp_test_seam_fclose.
*/
#define fclose smtp_test_seam_fclose
/**
* Redefine this function from smtp.c and inject a test seam which
* can control when this function fails.
*
* See @ref smtp_test_seam_ferror.
*/
#define ferror smtp_test_seam_ferror
/**
* Redefine this function from smtp.c and inject a test seam which
* can control when this function fails.
*
* See @ref smtp_test_seam_gmtime_r.
*/
#define gmtime_r smtp_test_seam_gmtime_r
/**
* Redefine this function from smtp.c and inject a test seam which
* can control when this function fails.
*
* See @ref smtp_test_seam_hmac.
*/
#define HMAC smtp_test_seam_hmac
/**
* Redefine this function from smtp.c and inject a test seam which
* can control when this function fails.
*
* See @ref smtp_test_seam_localtime_r.
*/
#define localtime_r smtp_test_seam_localtime_r
/**
* Redefine this function from smtp.c and inject a test seam which
* can control when this function fails.
*
* See @ref smtp_test_seam_malloc.
*/
#define malloc smtp_test_seam_malloc
/**
* Redefine this function from smtp.c and inject a test seam which
* can control when this function fails.
*
* See @ref smtp_test_seam_mktime.
*/
#define mktime smtp_test_seam_mktime
/**
* Redefine this function from smtp.c and inject a test seam which
* can control when this function fails.
*
* See @ref smtp_test_seam_realloc.
*/
#define realloc smtp_test_seam_realloc
/**
* Redefine this function from smtp.c and inject a test seam which
* can control when this function fails.
*
* See @ref smtp_test_seam_recv.
*/
#define recv smtp_test_seam_recv
/**
* Redefine this function from smtp.c and inject a test seam which
* can control when this function fails.
*
* See @ref smtp_test_seam_select.
*/
#define select smtp_test_seam_select
/**
* Redefine this function from smtp.c and inject a test seam which
* can control when this function fails.
*
* See @ref smtp_test_seam_send.
*/
#define send smtp_test_seam_send
/**
* Redefine this function from smtp.c and inject a test seam which
* can control when this function fails.
*
* See @ref smtp_test_seam_socket.
*/
#define socket smtp_test_seam_socket
/**
* Redefine this function from smtp.c and inject a test seam which
* can control when this function fails.
*
* See @ref smtp_test_seam_ssl_connect.
*/
#define SSL_connect smtp_test_seam_ssl_connect
/**
* Redefine this function from smtp.c and inject a test seam which
* can control when this function fails.
*
* See @ref smtp_test_seam_ssl_ctx_new.
*/
#define SSL_CTX_new smtp_test_seam_ssl_ctx_new
/**
* Redefine this function from smtp.c and inject a test seam which
* can control when this function fails.
*
* See @ref smtp_test_seam_ssl_do_handshake.
*/
#define SSL_do_handshake smtp_test_seam_ssl_do_handshake
/**
* Redefine this function from smtp.c and inject a test seam which
* can control when this function fails.
*
* See @ref smtp_test_seam_ssl_get_peer_certificate.
*/
#define SSL_get_peer_certificate smtp_test_seam_ssl_get_peer_certificate
/**
* Redefine this function from smtp.c and inject a test seam which
* can control when this function fails.
*
* See @ref smtp_test_seam_x509_check_host.
*/
#define X509_check_host smtp_test_seam_x509_check_host
/**
* Redefine this function from smtp.c and inject a test seam which
* can control when this function fails.
*
* See @ref smtp_test_seam_ssl_new.
*/
#define SSL_new smtp_test_seam_ssl_new
/**
* Redefine this function from smtp.c and inject a test seam which
* can control when this function fails.
*
* See @ref smtp_test_seam_ssl_read.
*/
#define SSL_read smtp_test_seam_ssl_read
/**
* Redefine this function from smtp.c and inject a test seam which
* can control when this function fails.
*
* See @ref smtp_test_seam_ssl_write.
*/
#define SSL_write smtp_test_seam_ssl_write
/**
* Redefine this function from smtp.c and inject a test seam which
* can control when this function fails.
*
* See @ref smtp_test_seam_sprintf.
*/
#define sprintf smtp_test_seam_sprintf
/**
* Redefine this function from smtp.c and inject a test seam which
* can control the return value of this function.
*
* See @ref smtp_test_seam_strlen.
*/
#define strlen smtp_test_seam_strlen
/**
* Redefine this function from smtp.c and inject a test seam which
* can control when this function fails.
*
* See @ref smtp_test_seam_time.
*/
#define time smtp_test_seam_time
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,577 @@
/**
* @file
* @brief Test the smtp-client library.
* @author James Humphrey (mail@somnisoft.com)
* @version 1.00
*
* This smtp-client testing framework has 100% branch coverage on POSIX
* systems. It requires a Postfix SMTP server that supports all of the
* connection security and authentication methods. These functional tests
* also require the user to manually check and ensure that the destination
* addresses received all of the test emails.
*
* This software has been placed into the public domain using CC0.
*
* @section test_seams_countdown_global
*
* The test harnesses control most of the test seams through the use of
* global counter values.
*
* Setting a global counter to -1 will make the test seam function operate
* as it normally would. If set to a positive value, the value will continue
* to decrement every time the function gets called. When the counter reaches
* 0, the test seam will force the function to return an error value.
*
* For example, initially setting the counter to 0 will force the test seam
* to return an error condition the first time it gets called. Setting the
* value to 1 initially will force the test seam to return an error condition
* on the second time it gets called.
*/
#ifndef SMTP_TEST_H
#define SMTP_TEST_H
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/types.h>
#include "../src/smtp.h"
#ifdef SMTP_OPENSSL
# include <openssl/bio.h>
# include <openssl/err.h>
# include <openssl/ssl.h>
# include <openssl/x509.h>
# include <openssl/x509v3.h>
#endif /* SMTP_OPENSSL */
struct smtp_command;
struct str_getdelimfd;
int
smtp_si_add_size_t(const size_t a,
const size_t b,
size_t *const result);
int
smtp_si_sub_size_t(const size_t a,
const size_t b,
size_t *const result);
int
smtp_si_mul_size_t(const size_t a,
const size_t b,
size_t *const result);
size_t
smtp_base64_decode(const char *const buf,
unsigned char **decode);
char *
smtp_base64_encode(const char *const buf,
size_t buflen);
char *
smtp_bin2hex(const unsigned char *const s,
size_t slen);
enum smtp_status_code
smtp_write(struct smtp *const smtp,
const char *const buf,
size_t len);
int
smtp_str_getdelimfd(struct str_getdelimfd *const gdfd);
int
smtp_str_getdelimfd_set_line_and_buf(struct str_getdelimfd *const gdfd,
size_t copy_len);
void
smtp_str_getdelimfd_free(struct str_getdelimfd *const gdfd);
char *
smtp_stpcpy(char *s1,
const char *s2);
void *
smtp_reallocarray(void *ptr,
size_t nmemb,
size_t size);
char *
smtp_strdup(const char *s);
char *
smtp_str_replace(const char *const search,
const char *const replace,
const char *const s);
size_t
smtp_utf8_charlen(char c);
int
smtp_str_has_nonascii_utf8(const char *const s);
size_t
smtp_strnlen_utf8(const char *s,
size_t maxlen);
size_t
smtp_fold_whitespace_get_offset(const char *const s,
unsigned int maxlen);
char *
smtp_fold_whitespace(const char *const s,
unsigned int maxlen);
char *
smtp_chunk_split(const char *const s,
size_t chunklen,
const char *const end);
char *
smtp_ffile_get_contents(FILE *stream,
size_t *bytes_read);
char *
smtp_file_get_contents(const char *const filename,
size_t *bytes_read);
int
smtp_parse_cmd_line(char *const line,
struct smtp_command *const cmd);
int
smtp_date_rfc_2822(char *const date);
int
smtp_address_validate_email(const char *const email);
int
smtp_address_validate_name(const char *const name);
int
smtp_attachment_validate_name(const char *const name);
int
smtp_header_key_validate(const char *const key);
int
smtp_header_value_validate(const char *const value);
/* test seams */
int
smtp_test_seam_dec_err_ctr(int *const test_err_ctr);
BIO *
smtp_test_seam_bio_new_socket(int sock,
int close_flag);
int
smtp_test_seam_bio_should_retry(BIO *bio);
void *
smtp_test_seam_calloc(size_t nelem,
size_t elsize);
int
smtp_test_seam_close(int fildes);
int
smtp_test_seam_connect(int socket,
const struct sockaddr *address,
socklen_t address_len);
unsigned long
smtp_test_seam_err_peek_error(void);
int
smtp_test_seam_fclose(FILE *stream);
int
smtp_test_seam_ferror(FILE *stream);
struct tm *
smtp_test_seam_gmtime_r(const time_t *timep,
struct tm *result);
unsigned char *
smtp_test_seam_hmac(const EVP_MD *evp_md,
const void *key,
int key_len,
const unsigned char *d,
size_t n,
unsigned char *md,
unsigned int *md_len);
struct tm *
smtp_test_seam_localtime_r(const time_t *timep,
struct tm *result);
void *
smtp_test_seam_malloc(size_t size);
time_t
smtp_test_seam_mktime(struct tm *timeptr);
void *
smtp_test_seam_realloc(void *ptr,
size_t size);
long
smtp_test_seam_recv(int socket,
void *buffer,
size_t length,
int flags);
int
smtp_test_seam_select(int nfds,
fd_set *readfds,
fd_set *writefds,
fd_set *errorfds,
struct timeval *timeout);
ssize_t
smtp_test_seam_send(int socket,
const void *buffer,
size_t length,
int flags);
int
smtp_test_seam_socket(int domain,
int type,
int protocol);
int
smtp_test_seam_ssl_connect(SSL *ssl);
SSL_CTX *
smtp_test_seam_ssl_ctx_new(const SSL_METHOD *method);
int
smtp_test_seam_ssl_do_handshake(SSL *ssl);
X509 *
smtp_test_seam_ssl_get_peer_certificate(const SSL *ssl);
int
smtp_test_seam_x509_check_host(X509 *cert,
const char *name,
size_t namelen,
unsigned int flags,
char **peername);
SSL *
smtp_test_seam_ssl_new(SSL_CTX *ctx);
int
smtp_test_seam_ssl_read(SSL *ssl,
void *buf,
int num);
int
smtp_test_seam_ssl_write(SSL *ssl,
const void *buf,
int num);
int
smtp_test_seam_sprintf(char *s,
const char *format, ...);
size_t
smtp_test_seam_strlen(const char *s);
time_t
smtp_test_seam_time(time_t *tloc);
/**
* Counter for @ref smtp_test_seam_bio_new_socket.
*
* See @ref test_seams_countdown_global for more details.
*/
extern int g_smtp_test_err_bio_new_socket_ctr;
/**
* Counter for @ref smtp_test_seam_bio_should_retry.
*
* See @ref test_seams_countdown_global for more details.
*/
extern int g_smtp_test_err_bio_should_retry_ctr;
/**
* Value to force the BIO_should_retry() function to return.
*
* This value will only get returned if
* @ref g_smtp_test_err_bio_should_retry_ctr
* has a value of 0 and this does not have a value of -1.
*/
extern int g_smtp_test_err_bio_should_retry_rc;
/**
* Counter for @ref smtp_test_seam_calloc.
*
* See @ref test_seams_countdown_global for more details.
*/
extern int g_smtp_test_err_calloc_ctr;
/**
* Counter for @ref smtp_test_seam_close.
*
* See @ref test_seams_countdown_global for more details.
*/
extern int g_smtp_test_err_close_ctr;
/**
* Counter for @ref smtp_test_seam_connect.
*
* See @ref test_seams_countdown_global for more details.
*/
extern int g_smtp_test_err_connect_ctr;
/**
* Counter for @ref smtp_test_seam_err_peek_error.
*
* See @ref test_seams_countdown_global for more details.
*/
extern int g_smtp_test_err_err_peek_error_ctr;
/**
* Counter for @ref smtp_test_seam_fclose.
*
* See @ref test_seams_countdown_global for more details.
*/
extern int g_smtp_test_err_fclose_ctr;
/**
* Counter for @ref smtp_test_seam_ferror.
*
* See @ref test_seams_countdown_global for more details.
*/
extern int g_smtp_test_err_ferror_ctr;
/**
* Counter for @ref smtp_test_seam_gmtime_r.
*
* See @ref test_seams_countdown_global for more details.
*/
extern int g_smtp_test_err_gmtime_r_ctr;
/**
* Counter for @ref smtp_test_seam_hmac.
*
* See @ref test_seams_countdown_global for more details.
*/
extern int g_smtp_test_err_hmac_ctr;
/**
* Counter for @ref smtp_test_seam_localtime_r.
*
* See @ref test_seams_countdown_global for more details.
*/
extern int g_smtp_test_err_localtime_r_ctr;
/**
* Counter for @ref smtp_test_seam_malloc.
*
* See @ref test_seams_countdown_global for more details.
*/
extern int g_smtp_test_err_malloc_ctr;
/**
* Counter for @ref smtp_test_seam_mktime.
*
* See @ref test_seams_countdown_global for more details.
*/
extern int g_smtp_test_err_mktime_ctr;
/**
* Counter for @ref smtp_test_seam_realloc.
*
* See @ref test_seams_countdown_global for more details.
*/
extern int g_smtp_test_err_realloc_ctr;
/**
* Counter for @ref smtp_test_seam_recv.
*
* See @ref test_seams_countdown_global for more details.
*/
extern int g_smtp_test_err_recv_ctr;
/**
* Value to force the recv() function to return.
*
* This value will only get returned if
* @ref g_smtp_test_err_recv_ctr
* has a value of 0 and this does not have a value of -1.
*/
extern int g_smtp_test_err_recv_rc;
/**
* Set the received bytes in recv() and SSL_read() to this value if it
* contains a null-terminated string at least one bytes long.
*
* This makes it easier to inject a bad server response for testing the
* smtp-client handling of those bad responses.
*
* See @ref test_seams_countdown_global for more details.
*/
extern char g_smtp_test_err_recv_bytes[90];
/**
* Counter for @ref smtp_test_seam_select.
*
* See @ref test_seams_countdown_global for more details.
*/
extern int g_smtp_test_err_select_ctr;
/**
* Counter for @ref smtp_test_seam_send.
*
* See @ref test_seams_countdown_global for more details.
*/
extern int g_smtp_test_err_send_ctr;
/**
* Indicate if we should only send one byte at a time.
*/
extern int g_smtp_test_send_one_byte;
/**
* Counter for @ref smtp_si_add_size_t.
*
* See @ref test_seams_countdown_global for more details.
*/
extern int g_smtp_test_err_si_add_size_t_ctr;
/**
* Counter for @ref smtp_si_sub_size_t.
*
* See @ref test_seams_countdown_global for more details.
*/
extern int g_smtp_test_err_si_sub_size_t_ctr;
/**
* Counter for @ref smtp_si_mul_size_t.
*
* See @ref test_seams_countdown_global for more details.
*/
extern int g_smtp_test_err_si_mul_size_t_ctr;
/**
* Counter for @ref smtp_test_seam_socket.
*
* See @ref test_seams_countdown_global for more details.
*/
extern int g_smtp_test_err_socket_ctr;
/**
* Counter for @ref smtp_test_seam_ssl_connect.
*
* See @ref test_seams_countdown_global for more details.
*/
extern int g_smtp_test_err_ssl_connect_ctr;
/**
* Counter for @ref smtp_test_seam_ssl_ctx_new.
*
* See @ref test_seams_countdown_global for more details.
*/
extern int g_smtp_test_err_ssl_ctx_new_ctr;
/**
* Counter for @ref smtp_test_seam_ssl_do_handshake.
*
* See @ref test_seams_countdown_global for more details.
*/
extern int g_smtp_test_err_ssl_do_handshake_ctr;
/**
* Counter for @ref smtp_test_seam_ssl_get_peer_certificate.
*
* See @ref test_seams_countdown_global for more details.
*/
extern int g_smtp_test_err_ssl_get_peer_certificate_ctr;
/**
* Counter for @ref smtp_test_seam_x509_check_host.
*
* See @ref test_seams_countdown_global for more details.
*/
extern int g_smtp_test_err_x509_check_host_ctr;
/**
* Counter for @ref smtp_test_seam_ssl_new.
*
* See @ref test_seams_countdown_global for more details.
*/
extern int g_smtp_test_err_ssl_new_ctr;
/**
* Counter for @ref smtp_test_seam_ssl_read.
*
* See @ref test_seams_countdown_global for more details.
*/
extern int g_smtp_test_err_ssl_read_ctr;
/**
* Counter for @ref smtp_test_seam_ssl_write.
*
* See @ref test_seams_countdown_global for more details.
*/
extern int g_smtp_test_err_ssl_write_ctr;
/**
* Counter for @ref smtp_test_seam_sprintf.
*
* See @ref test_seams_countdown_global for more details.
*/
extern int g_smtp_test_err_sprintf_ctr;
/**
* Value to force the sprintf() function to return.
*
* This value will only get returned if @ref g_smtp_test_err_sprintf_ctr has
* a value of 0.
*/
extern int g_smtp_test_err_sprintf_rc;
/**
* Indicates if the strlen() function should return a test value.
*
* This can get set to one of two values:
* - 0 - The strlen() function will operate normally.
* - !0 - The strlen() function will return the value specified in
* @ref g_smtp_test_strlen_ret_value.
*/
extern int g_smtp_test_strlen_custom_ret;
/**
* Value to force the strlen() function to return.
*
* This value will only get returned if @ref g_smtp_test_strlen_custom_ret
* has been set.
*/
extern size_t g_smtp_test_strlen_ret_value;
/**
* Indicates if the time() function should return a custom value.
*
* This can get set to one of two values:
* - 0 - The time() function will operate normally.
* - !0 - The time() function will return the value specified in
* @ref g_smtp_test_time_ret_value.
*/
extern int g_smtp_test_time_custom_ret;
/**
* Value to force the time() function to return.
*
* This value will only get returned if @ref g_smtp_test_time_custom_ret has
* a positive value.
*/
extern time_t g_smtp_test_time_ret_value;
#endif /* SMTP_TEST_H */

Binary file not shown.

View File

@@ -0,0 +1,49 @@
/**
* @file
* @brief Test the smtp-client CPP wrapper.
* @author James Humphrey (mail@somnisoft.com)
* @version 1.00
*
* Example program demonstrating how to use the CPP wrapper class.
*
* This software has been placed into the public domain using CC0.
*/
#include <err.h>
#include <SMTPMail.h>
/**
* Main program entry point for the example smtp-client CPP class wrapper.
*
* @param[in] argc Number of arguments in @p argv.
* @param[in] argv String array containing the program name and any optional
* parameters described above.
* @retval 0 Email has been sent.
* @retval 1 An error occurred while sending email. Although unlikely, an email
* can still get sent even after returning with this error code.
*/
int main(int argc, char *argv[]){
SMTPMail *mail;
mail = new SMTPMail();
try{
mail->open("localhost", "25", SMTP_SECURITY_NONE, SMTP_DEBUG, NULL);
mail->auth(SMTP_AUTH_NONE, NULL, NULL);
mail->address_add(SMTP_ADDRESS_FROM,
"mail@somnisoft.com",
"From Address");
mail->address_add(SMTP_ADDRESS_TO,
"mail@somnisoft.com",
"To Address");
mail->header_add("Subject", "Test email (SMTPMail)");
mail->mail("Email sent using CPP SMTPMail class");
mail->close();
}
catch(SMTPMailException sme){
errx(1, "Failed to send email: %s\n", sme.what());
}
delete mail;
return 0;
}

View File

@@ -0,0 +1,102 @@
/**
* @file
* @brief Test the smtp-client library without OpenSSL.
* @author James Humphrey (mail@somnisoft.com)
* @version 1.00
*
* These functional tests ensure that the smtp-client library works when
* configured without OpenSSL.
*
* This software has been placed into the public domain using CC0.
*/
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <smtp.h>
/**
* Load the test email to send from a configuration file.
*
* @param[out] email String buffer to store the email in.
* @param[in] emailsz Number of bytes in email.
*/
static void
load_test_email(char *const email,
size_t emailsz){
FILE *fp;
int rc;
size_t bytes_read;
fp = fopen("test/config/test_email.txt", "r");
assert(fp);
bytes_read = fread(email, sizeof(*email), emailsz, fp);
assert(bytes_read > 0);
email[bytes_read - 1] = '\0';
rc = ferror(fp);
assert(rc == 0);
rc = fclose(fp);
assert(rc == 0);
}
/**
* Load the configuration file and send a single test email.
*/
static void
test_nossl_smtp(void){
int rc;
struct smtp *smtp;
char email[1000];
load_test_email(email, sizeof(email));
rc = smtp_open("localhost",
"25",
SMTP_SECURITY_NONE,
SMTP_DEBUG,
NULL,
&smtp);
assert(rc == SMTP_STATUS_OK);
rc = smtp_address_add(smtp,
SMTP_ADDRESS_FROM,
email,
"Test Email");
assert(rc == SMTP_STATUS_OK);
rc = smtp_address_add(smtp,
SMTP_ADDRESS_TO,
email,
"Test Email");
assert(rc == SMTP_STATUS_OK);
rc = smtp_header_add(smtp,
"Subject",
"SMTP Test: Build Without OpenSSL");
assert(rc == SMTP_STATUS_OK);
rc = smtp_mail(smtp,
"This email tests the build without OpenSSL compiled into"
" the library.");
assert(rc == SMTP_STATUS_OK);
rc = smtp_close(smtp);
assert(rc == SMTP_STATUS_OK);
}
/**
* Main program entry point for testing the smtp-client library
* build without OpenSSL.
*
* @retval 0 All tests passed.
* @retval 1 Error.
*/
int main(void){
test_nossl_smtp();
return 0;
}

View File

@@ -0,0 +1,24 @@
{
OpenSSL malloc
Memcheck:Leak
fun:malloc
fun:CRYPTO_malloc
...
obj:*libcrypto*
}
{
OpenSSL zalloc
Memcheck:Leak
fun:malloc
fun:CRYPTO_zalloc
...
obj:*libcrypto*
}
{
OpenSSL realloc
Memcheck:Leak
fun:realloc
fun:CRYPTO_realloc
...
obj:*libcrypto*
}

View File

@@ -0,0 +1,35 @@
#ifndef NACL_H
#define NACL_H
#include <random>
extern "C" {
// for tweetnacl
#include "tweetnacl.h"
void randombytes(unsigned char* x, unsigned long long xlen)
{
std::random_device rd;
std::uniform_int_distribution<unsigned int> dist(
std::numeric_limits<unsigned int>::min(),
std::numeric_limits<unsigned int>::max());
while (xlen > 0)
{
unsigned int number = dist(rd);
for (size_t i = sizeof(unsigned int); i > 0 ; i--)
{
unsigned char byteValue = (number >> (i - 1) * 8) & 0xFF;
*x = byteValue;
x += 1;
xlen -= 1;
if (xlen <= 0)
break;
}
}
}
}
#endif

View File

@@ -0,0 +1,809 @@
#include "tweetnacl.h"
#define FOR(i,n) for (i = 0;i < n;++i)
#define sv static void
typedef unsigned char u8;
typedef unsigned long u32;
typedef unsigned long long u64;
typedef long long i64;
typedef i64 gf[16];
extern void randombytes(u8 *,u64);
static const u8
_0[16],
_9[32] = {9};
static const gf
gf0,
gf1 = {1},
_121665 = {0xDB41,1},
D = {0x78a3, 0x1359, 0x4dca, 0x75eb, 0xd8ab, 0x4141, 0x0a4d, 0x0070, 0xe898, 0x7779, 0x4079, 0x8cc7, 0xfe73, 0x2b6f, 0x6cee, 0x5203},
D2 = {0xf159, 0x26b2, 0x9b94, 0xebd6, 0xb156, 0x8283, 0x149a, 0x00e0, 0xd130, 0xeef3, 0x80f2, 0x198e, 0xfce7, 0x56df, 0xd9dc, 0x2406},
X = {0xd51a, 0x8f25, 0x2d60, 0xc956, 0xa7b2, 0x9525, 0xc760, 0x692c, 0xdc5c, 0xfdd6, 0xe231, 0xc0a4, 0x53fe, 0xcd6e, 0x36d3, 0x2169},
Y = {0x6658, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666, 0x6666},
I = {0xa0b0, 0x4a0e, 0x1b27, 0xc4ee, 0xe478, 0xad2f, 0x1806, 0x2f43, 0xd7a7, 0x3dfb, 0x0099, 0x2b4d, 0xdf0b, 0x4fc1, 0x2480, 0x2b83};
static u32 L32(u32 x,int c) { return (x << c) | ((x&0xffffffff) >> (32 - c)); }
static u32 ld32(const u8 *x)
{
u32 u = x[3];
u = (u<<8)|x[2];
u = (u<<8)|x[1];
return (u<<8)|x[0];
}
static u64 dl64(const u8 *x)
{
u64 i,u=0;
FOR(i,8) u=(u<<8)|x[i];
return u;
}
sv st32(u8 *x,u32 u)
{
int i;
FOR(i,4) { x[i] = u; u >>= 8; }
}
sv ts64(u8 *x,u64 u)
{
int i;
for (i = 7;i >= 0;--i) { x[i] = u; u >>= 8; }
}
static int vn(const u8 *x,const u8 *y,int n)
{
u32 i,d = 0;
FOR(i,n) d |= x[i]^y[i];
return (1 & ((d - 1) >> 8)) - 1;
}
int crypto_verify_16(const u8 *x,const u8 *y)
{
return vn(x,y,16);
}
int crypto_verify_32(const u8 *x,const u8 *y)
{
return vn(x,y,32);
}
sv core(u8 *out,const u8 *in,const u8 *k,const u8 *c,int h)
{
u32 w[16],x[16],y[16],t[4];
int i,j,m;
FOR(i,4) {
x[5*i] = ld32(c+4*i);
x[1+i] = ld32(k+4*i);
x[6+i] = ld32(in+4*i);
x[11+i] = ld32(k+16+4*i);
}
FOR(i,16) y[i] = x[i];
FOR(i,20) {
FOR(j,4) {
FOR(m,4) t[m] = x[(5*j+4*m)%16];
t[1] ^= L32(t[0]+t[3], 7);
t[2] ^= L32(t[1]+t[0], 9);
t[3] ^= L32(t[2]+t[1],13);
t[0] ^= L32(t[3]+t[2],18);
FOR(m,4) w[4*j+(j+m)%4] = t[m];
}
FOR(m,16) x[m] = w[m];
}
if (h) {
FOR(i,16) x[i] += y[i];
FOR(i,4) {
x[5*i] -= ld32(c+4*i);
x[6+i] -= ld32(in+4*i);
}
FOR(i,4) {
st32(out+4*i,x[5*i]);
st32(out+16+4*i,x[6+i]);
}
} else
FOR(i,16) st32(out + 4 * i,x[i] + y[i]);
}
int crypto_core_salsa20(u8 *out,const u8 *in,const u8 *k,const u8 *c)
{
core(out,in,k,c,0);
return 0;
}
int crypto_core_hsalsa20(u8 *out,const u8 *in,const u8 *k,const u8 *c)
{
core(out,in,k,c,1);
return 0;
}
static const u8 sigma[16] = "expand 32-byte k";
int crypto_stream_salsa20_xor(u8 *c,const u8 *m,u64 b,const u8 *n,const u8 *k)
{
u8 z[16],x[64];
u32 u,i;
if (!b) return 0;
FOR(i,16) z[i] = 0;
FOR(i,8) z[i] = n[i];
while (b >= 64) {
crypto_core_salsa20(x,z,k,sigma);
FOR(i,64) c[i] = (m?m[i]:0) ^ x[i];
u = 1;
for (i = 8;i < 16;++i) {
u += (u32) z[i];
z[i] = u;
u >>= 8;
}
b -= 64;
c += 64;
if (m) m += 64;
}
if (b) {
crypto_core_salsa20(x,z,k,sigma);
FOR(i,b) c[i] = (m?m[i]:0) ^ x[i];
}
return 0;
}
int crypto_stream_salsa20(u8 *c,u64 d,const u8 *n,const u8 *k)
{
return crypto_stream_salsa20_xor(c,0,d,n,k);
}
int crypto_stream(u8 *c,u64 d,const u8 *n,const u8 *k)
{
u8 s[32];
crypto_core_hsalsa20(s,n,k,sigma);
return crypto_stream_salsa20(c,d,n+16,s);
}
int crypto_stream_xor(u8 *c,const u8 *m,u64 d,const u8 *n,const u8 *k)
{
u8 s[32];
crypto_core_hsalsa20(s,n,k,sigma);
return crypto_stream_salsa20_xor(c,m,d,n+16,s);
}
sv add1305(u32 *h,const u32 *c)
{
u32 j,u = 0;
FOR(j,17) {
u += h[j] + c[j];
h[j] = u & 255;
u >>= 8;
}
}
static const u32 minusp[17] = {
5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 252
} ;
int crypto_onetimeauth(u8 *out,const u8 *m,u64 n,const u8 *k)
{
u32 s,i,j,u,x[17],r[17],h[17],c[17],g[17];
FOR(j,17) r[j]=h[j]=0;
FOR(j,16) r[j]=k[j];
r[3]&=15;
r[4]&=252;
r[7]&=15;
r[8]&=252;
r[11]&=15;
r[12]&=252;
r[15]&=15;
while (n > 0) {
FOR(j,17) c[j] = 0;
for (j = 0;(j < 16) && (j < n);++j) c[j] = m[j];
c[j] = 1;
m += j; n -= j;
add1305(h,c);
FOR(i,17) {
x[i] = 0;
FOR(j,17) x[i] += h[j] * ((j <= i) ? r[i - j] : 320 * r[i + 17 - j]);
}
FOR(i,17) h[i] = x[i];
u = 0;
FOR(j,16) {
u += h[j];
h[j] = u & 255;
u >>= 8;
}
u += h[16]; h[16] = u & 3;
u = 5 * (u >> 2);
FOR(j,16) {
u += h[j];
h[j] = u & 255;
u >>= 8;
}
u += h[16]; h[16] = u;
}
FOR(j,17) g[j] = h[j];
add1305(h,minusp);
s = -(h[16] >> 7);
FOR(j,17) h[j] ^= s & (g[j] ^ h[j]);
FOR(j,16) c[j] = k[j + 16];
c[16] = 0;
add1305(h,c);
FOR(j,16) out[j] = h[j];
return 0;
}
int crypto_onetimeauth_verify(const u8 *h,const u8 *m,u64 n,const u8 *k)
{
u8 x[16];
crypto_onetimeauth(x,m,n,k);
return crypto_verify_16(h,x);
}
int crypto_secretbox(u8 *c,const u8 *m,u64 d,const u8 *n,const u8 *k)
{
int i;
if (d < 32) return -1;
crypto_stream_xor(c,m,d,n,k);
crypto_onetimeauth(c + 16,c + 32,d - 32,c);
FOR(i,16) c[i] = 0;
return 0;
}
int crypto_secretbox_open(u8 *m,const u8 *c,u64 d,const u8 *n,const u8 *k)
{
int i;
u8 x[32];
if (d < 32) return -1;
crypto_stream(x,32,n,k);
if (crypto_onetimeauth_verify(c + 16,c + 32,d - 32,x) != 0) return -1;
crypto_stream_xor(m,c,d,n,k);
FOR(i,32) m[i] = 0;
return 0;
}
sv set25519(gf r, const gf a)
{
int i;
FOR(i,16) r[i]=a[i];
}
sv car25519(gf o)
{
int i;
i64 c;
FOR(i,16) {
o[i]+=(1LL<<16);
c=o[i]>>16;
o[(i+1)*(i<15)]+=c-1+37*(c-1)*(i==15);
o[i]-=c<<16;
}
}
sv sel25519(gf p,gf q,int b)
{
i64 t,i,c=~(b-1);
FOR(i,16) {
t= c&(p[i]^q[i]);
p[i]^=t;
q[i]^=t;
}
}
sv pack25519(u8 *o,const gf n)
{
int i,j,b;
gf m,t;
FOR(i,16) t[i]=n[i];
car25519(t);
car25519(t);
car25519(t);
FOR(j,2) {
m[0]=t[0]-0xffed;
for(i=1;i<15;i++) {
m[i]=t[i]-0xffff-((m[i-1]>>16)&1);
m[i-1]&=0xffff;
}
m[15]=t[15]-0x7fff-((m[14]>>16)&1);
b=(m[15]>>16)&1;
m[14]&=0xffff;
sel25519(t,m,1-b);
}
FOR(i,16) {
o[2*i]=t[i]&0xff;
o[2*i+1]=t[i]>>8;
}
}
static int neq25519(const gf a, const gf b)
{
u8 c[32],d[32];
pack25519(c,a);
pack25519(d,b);
return crypto_verify_32(c,d);
}
static u8 par25519(const gf a)
{
u8 d[32];
pack25519(d,a);
return d[0]&1;
}
sv unpack25519(gf o, const u8 *n)
{
int i;
FOR(i,16) o[i]=n[2*i]+((i64)n[2*i+1]<<8);
o[15]&=0x7fff;
}
sv A(gf o,const gf a,const gf b)
{
int i;
FOR(i,16) o[i]=a[i]+b[i];
}
sv Z(gf o,const gf a,const gf b)
{
int i;
FOR(i,16) o[i]=a[i]-b[i];
}
sv M(gf o,const gf a,const gf b)
{
i64 i,j,t[31];
FOR(i,31) t[i]=0;
FOR(i,16) FOR(j,16) t[i+j]+=a[i]*b[j];
FOR(i,15) t[i]+=38*t[i+16];
FOR(i,16) o[i]=t[i];
car25519(o);
car25519(o);
}
sv S(gf o,const gf a)
{
M(o,a,a);
}
sv inv25519(gf o,const gf i)
{
gf c;
int a;
FOR(a,16) c[a]=i[a];
for(a=253;a>=0;a--) {
S(c,c);
if(a!=2&&a!=4) M(c,c,i);
}
FOR(a,16) o[a]=c[a];
}
sv pow2523(gf o,const gf i)
{
gf c;
int a;
FOR(a,16) c[a]=i[a];
for(a=250;a>=0;a--) {
S(c,c);
if(a!=1) M(c,c,i);
}
FOR(a,16) o[a]=c[a];
}
int crypto_scalarmult(u8 *q,const u8 *n,const u8 *p)
{
u8 z[32];
i64 x[80],r,i;
gf a,b,c,d,e,f;
FOR(i,31) z[i]=n[i];
z[31]=(n[31]&127)|64;
z[0]&=248;
unpack25519(x,p);
FOR(i,16) {
b[i]=x[i];
d[i]=a[i]=c[i]=0;
}
a[0]=d[0]=1;
for(i=254;i>=0;--i) {
r=(z[i>>3]>>(i&7))&1;
sel25519(a,b,r);
sel25519(c,d,r);
A(e,a,c);
Z(a,a,c);
A(c,b,d);
Z(b,b,d);
S(d,e);
S(f,a);
M(a,c,a);
M(c,b,e);
A(e,a,c);
Z(a,a,c);
S(b,a);
Z(c,d,f);
M(a,c,_121665);
A(a,a,d);
M(c,c,a);
M(a,d,f);
M(d,b,x);
S(b,e);
sel25519(a,b,r);
sel25519(c,d,r);
}
FOR(i,16) {
x[i+16]=a[i];
x[i+32]=c[i];
x[i+48]=b[i];
x[i+64]=d[i];
}
inv25519(x+32,x+32);
M(x+16,x+16,x+32);
pack25519(q,x+16);
return 0;
}
int crypto_scalarmult_base(u8 *q,const u8 *n)
{
return crypto_scalarmult(q,n,_9);
}
int crypto_box_keypair(u8 *y,u8 *x)
{
randombytes(x,32);
return crypto_scalarmult_base(y,x);
}
int crypto_box_beforenm(u8 *k,const u8 *y,const u8 *x)
{
u8 s[32];
crypto_scalarmult(s,x,y);
return crypto_core_hsalsa20(k,_0,s,sigma);
}
int crypto_box_afternm(u8 *c,const u8 *m,u64 d,const u8 *n,const u8 *k)
{
return crypto_secretbox(c,m,d,n,k);
}
int crypto_box_open_afternm(u8 *m,const u8 *c,u64 d,const u8 *n,const u8 *k)
{
return crypto_secretbox_open(m,c,d,n,k);
}
int crypto_box(u8 *c,const u8 *m,u64 d,const u8 *n,const u8 *y,const u8 *x)
{
u8 k[32];
crypto_box_beforenm(k,y,x);
return crypto_box_afternm(c,m,d,n,k);
}
int crypto_box_open(u8 *m,const u8 *c,u64 d,const u8 *n,const u8 *y,const u8 *x)
{
u8 k[32];
crypto_box_beforenm(k,y,x);
return crypto_box_open_afternm(m,c,d,n,k);
}
static u64 R(u64 x,int c) { return (x >> c) | (x << (64 - c)); }
static u64 Ch(u64 x,u64 y,u64 z) { return (x & y) ^ (~x & z); }
static u64 Maj(u64 x,u64 y,u64 z) { return (x & y) ^ (x & z) ^ (y & z); }
static u64 Sigma0(u64 x) { return R(x,28) ^ R(x,34) ^ R(x,39); }
static u64 Sigma1(u64 x) { return R(x,14) ^ R(x,18) ^ R(x,41); }
static u64 sigma0(u64 x) { return R(x, 1) ^ R(x, 8) ^ (x >> 7); }
static u64 sigma1(u64 x) { return R(x,19) ^ R(x,61) ^ (x >> 6); }
static const u64 K[80] =
{
0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL,
0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL,
0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL,
0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,
0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL,
0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL,
0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,
0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL,
0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL,
0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL,
0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL,
0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL,
0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL,
0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL
};
int crypto_hashblocks(u8 *x,const u8 *m,u64 n)
{
u64 z[8],b[8],a[8],w[16],t;
int i,j;
FOR(i,8) z[i] = a[i] = dl64(x + 8 * i);
while (n >= 128) {
FOR(i,16) w[i] = dl64(m + 8 * i);
FOR(i,80) {
FOR(j,8) b[j] = a[j];
t = a[7] + Sigma1(a[4]) + Ch(a[4],a[5],a[6]) + K[i] + w[i%16];
b[7] = t + Sigma0(a[0]) + Maj(a[0],a[1],a[2]);
b[3] += t;
FOR(j,8) a[(j+1)%8] = b[j];
if (i%16 == 15)
FOR(j,16)
w[j] += w[(j+9)%16] + sigma0(w[(j+1)%16]) + sigma1(w[(j+14)%16]);
}
FOR(i,8) { a[i] += z[i]; z[i] = a[i]; }
m += 128;
n -= 128;
}
FOR(i,8) ts64(x+8*i,z[i]);
return n;
}
static const u8 iv[64] = {
0x6a,0x09,0xe6,0x67,0xf3,0xbc,0xc9,0x08,
0xbb,0x67,0xae,0x85,0x84,0xca,0xa7,0x3b,
0x3c,0x6e,0xf3,0x72,0xfe,0x94,0xf8,0x2b,
0xa5,0x4f,0xf5,0x3a,0x5f,0x1d,0x36,0xf1,
0x51,0x0e,0x52,0x7f,0xad,0xe6,0x82,0xd1,
0x9b,0x05,0x68,0x8c,0x2b,0x3e,0x6c,0x1f,
0x1f,0x83,0xd9,0xab,0xfb,0x41,0xbd,0x6b,
0x5b,0xe0,0xcd,0x19,0x13,0x7e,0x21,0x79
} ;
int crypto_hash(u8 *out,const u8 *m,u64 n)
{
u8 h[64],x[256];
u64 i,b = n;
FOR(i,64) h[i] = iv[i];
crypto_hashblocks(h,m,n);
m += n;
n &= 127;
m -= n;
FOR(i,256) x[i] = 0;
FOR(i,n) x[i] = m[i];
x[n] = 128;
n = 256-128*(n<112);
x[n-9] = b >> 61;
ts64(x+n-8,b<<3);
crypto_hashblocks(h,x,n);
FOR(i,64) out[i] = h[i];
return 0;
}
sv add(gf p[4],gf q[4])
{
gf a,b,c,d,t,e,f,g,h;
Z(a, p[1], p[0]);
Z(t, q[1], q[0]);
M(a, a, t);
A(b, p[0], p[1]);
A(t, q[0], q[1]);
M(b, b, t);
M(c, p[3], q[3]);
M(c, c, D2);
M(d, p[2], q[2]);
A(d, d, d);
Z(e, b, a);
Z(f, d, c);
A(g, d, c);
A(h, b, a);
M(p[0], e, f);
M(p[1], h, g);
M(p[2], g, f);
M(p[3], e, h);
}
sv cswap(gf p[4],gf q[4],u8 b)
{
int i;
FOR(i,4)
sel25519(p[i],q[i],b);
}
sv pack(u8 *r,gf p[4])
{
gf tx, ty, zi;
inv25519(zi, p[2]);
M(tx, p[0], zi);
M(ty, p[1], zi);
pack25519(r, ty);
r[31] ^= par25519(tx) << 7;
}
sv scalarmult(gf p[4],gf q[4],const u8 *s)
{
int i;
set25519(p[0],gf0);
set25519(p[1],gf1);
set25519(p[2],gf1);
set25519(p[3],gf0);
for (i = 255;i >= 0;--i) {
u8 b = (s[i/8]>>(i&7))&1;
cswap(p,q,b);
add(q,p);
add(p,p);
cswap(p,q,b);
}
}
sv scalarbase(gf p[4],const u8 *s)
{
gf q[4];
set25519(q[0],X);
set25519(q[1],Y);
set25519(q[2],gf1);
M(q[3],X,Y);
scalarmult(p,q,s);
}
int crypto_sign_keypair(u8 *pk, u8 *sk)
{
u8 d[64];
gf p[4];
int i;
randombytes(sk, 32);
crypto_hash(d, sk, 32);
d[0] &= 248;
d[31] &= 127;
d[31] |= 64;
scalarbase(p,d);
pack(pk,p);
FOR(i,32) sk[32 + i] = pk[i];
return 0;
}
static const u64 L[32] = {0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10};
sv modL(u8 *r,i64 x[64])
{
i64 carry,i,j;
for (i = 63;i >= 32;--i) {
carry = 0;
for (j = i - 32;j < i - 12;++j) {
x[j] += carry - 16 * x[i] * L[j - (i - 32)];
carry = (x[j] + 128) >> 8;
x[j] -= carry << 8;
}
x[j] += carry;
x[i] = 0;
}
carry = 0;
FOR(j,32) {
x[j] += carry - (x[31] >> 4) * L[j];
carry = x[j] >> 8;
x[j] &= 255;
}
FOR(j,32) x[j] -= carry * L[j];
FOR(i,32) {
x[i+1] += x[i] >> 8;
r[i] = x[i] & 255;
}
}
sv reduce(u8 *r)
{
i64 x[64],i;
FOR(i,64) x[i] = (u64) r[i];
FOR(i,64) r[i] = 0;
modL(r,x);
}
int crypto_sign(u8 *sm,u64 *smlen,const u8 *m,u64 n,const u8 *sk)
{
u8 d[64],h[64],r[64];
i64 i,j,x[64];
gf p[4];
crypto_hash(d, sk, 32);
d[0] &= 248;
d[31] &= 127;
d[31] |= 64;
*smlen = n+64;
FOR(i,n) sm[64 + i] = m[i];
FOR(i,32) sm[32 + i] = d[32 + i];
crypto_hash(r, sm+32, n+32);
reduce(r);
scalarbase(p,r);
pack(sm,p);
FOR(i,32) sm[i+32] = sk[i+32];
crypto_hash(h,sm,n + 64);
reduce(h);
FOR(i,64) x[i] = 0;
FOR(i,32) x[i] = (u64) r[i];
FOR(i,32) FOR(j,32) x[i+j] += h[i] * (u64) d[j];
modL(sm + 32,x);
return 0;
}
static int unpackneg(gf r[4],const u8 p[32])
{
gf t, chk, num, den, den2, den4, den6;
set25519(r[2],gf1);
unpack25519(r[1],p);
S(num,r[1]);
M(den,num,D);
Z(num,num,r[2]);
A(den,r[2],den);
S(den2,den);
S(den4,den2);
M(den6,den4,den2);
M(t,den6,num);
M(t,t,den);
pow2523(t,t);
M(t,t,num);
M(t,t,den);
M(t,t,den);
M(r[0],t,den);
S(chk,r[0]);
M(chk,chk,den);
if (neq25519(chk, num)) M(r[0],r[0],I);
S(chk,r[0]);
M(chk,chk,den);
if (neq25519(chk, num)) return -1;
if (par25519(r[0]) == (p[31]>>7)) Z(r[0],gf0,r[0]);
M(r[3],r[0],r[1]);
return 0;
}
int crypto_sign_open(u8 *m,u64 *mlen,const u8 *sm,u64 n,const u8 *pk)
{
int i;
u8 t[32],h[64];
gf p[4],q[4];
*mlen = -1;
if (n < 64) return -1;
if (unpackneg(q,pk)) return -1;
FOR(i,n) m[i] = sm[i];
FOR(i,32) m[i+32] = pk[i];
crypto_hash(h,m,n);
reduce(h);
scalarmult(p,q,h);
scalarbase(q,sm + 32);
add(p,q);
pack(t,p);
n -= 64;
if (crypto_verify_32(sm, t)) {
FOR(i,n) m[i] = 0;
return -1;
}
FOR(i,n) m[i] = sm[i + 64];
*mlen = n;
return 0;
}

View File

@@ -0,0 +1,272 @@
#ifndef TWEETNACL_H
#define TWEETNACL_H
#define crypto_auth_PRIMITIVE "hmacsha512256"
#define crypto_auth crypto_auth_hmacsha512256
#define crypto_auth_verify crypto_auth_hmacsha512256_verify
#define crypto_auth_BYTES crypto_auth_hmacsha512256_BYTES
#define crypto_auth_KEYBYTES crypto_auth_hmacsha512256_KEYBYTES
#define crypto_auth_IMPLEMENTATION crypto_auth_hmacsha512256_IMPLEMENTATION
#define crypto_auth_VERSION crypto_auth_hmacsha512256_VERSION
#define crypto_auth_hmacsha512256_tweet_BYTES 32
#define crypto_auth_hmacsha512256_tweet_KEYBYTES 32
extern int crypto_auth_hmacsha512256_tweet(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *);
extern int crypto_auth_hmacsha512256_tweet_verify(const unsigned char *,const unsigned char *,unsigned long long,const unsigned char *);
#define crypto_auth_hmacsha512256_tweet_VERSION "-"
#define crypto_auth_hmacsha512256 crypto_auth_hmacsha512256_tweet
#define crypto_auth_hmacsha512256_verify crypto_auth_hmacsha512256_tweet_verify
#define crypto_auth_hmacsha512256_BYTES crypto_auth_hmacsha512256_tweet_BYTES
#define crypto_auth_hmacsha512256_KEYBYTES crypto_auth_hmacsha512256_tweet_KEYBYTES
#define crypto_auth_hmacsha512256_VERSION crypto_auth_hmacsha512256_tweet_VERSION
#define crypto_auth_hmacsha512256_IMPLEMENTATION "crypto_auth/hmacsha512256/tweet"
#define crypto_box_PRIMITIVE "curve25519xsalsa20poly1305"
#define crypto_box crypto_box_curve25519xsalsa20poly1305
#define crypto_box_open crypto_box_curve25519xsalsa20poly1305_open
#define crypto_box_keypair crypto_box_curve25519xsalsa20poly1305_keypair
#define crypto_box_beforenm crypto_box_curve25519xsalsa20poly1305_beforenm
#define crypto_box_afternm crypto_box_curve25519xsalsa20poly1305_afternm
#define crypto_box_open_afternm crypto_box_curve25519xsalsa20poly1305_open_afternm
#define crypto_box_PUBLICKEYBYTES crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES
#define crypto_box_SECRETKEYBYTES crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES
#define crypto_box_BEFORENMBYTES crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES
#define crypto_box_NONCEBYTES crypto_box_curve25519xsalsa20poly1305_NONCEBYTES
#define crypto_box_ZEROBYTES crypto_box_curve25519xsalsa20poly1305_ZEROBYTES
#define crypto_box_BOXZEROBYTES crypto_box_curve25519xsalsa20poly1305_BOXZEROBYTES
#define crypto_box_IMPLEMENTATION crypto_box_curve25519xsalsa20poly1305_IMPLEMENTATION
#define crypto_box_VERSION crypto_box_curve25519xsalsa20poly1305_VERSION
#define crypto_box_curve25519xsalsa20poly1305_tweet_PUBLICKEYBYTES 32
#define crypto_box_curve25519xsalsa20poly1305_tweet_SECRETKEYBYTES 32
#define crypto_box_curve25519xsalsa20poly1305_tweet_BEFORENMBYTES 32
#define crypto_box_curve25519xsalsa20poly1305_tweet_NONCEBYTES 24
#define crypto_box_curve25519xsalsa20poly1305_tweet_ZEROBYTES 32
#define crypto_box_curve25519xsalsa20poly1305_tweet_BOXZEROBYTES 16
extern int crypto_box_curve25519xsalsa20poly1305_tweet(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *,const unsigned char *);
extern int crypto_box_curve25519xsalsa20poly1305_tweet_open(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *,const unsigned char *);
extern int crypto_box_curve25519xsalsa20poly1305_tweet_keypair(unsigned char *,unsigned char *);
extern int crypto_box_curve25519xsalsa20poly1305_tweet_beforenm(unsigned char *,const unsigned char *,const unsigned char *);
extern int crypto_box_curve25519xsalsa20poly1305_tweet_afternm(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *);
extern int crypto_box_curve25519xsalsa20poly1305_tweet_open_afternm(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *);
#define crypto_box_curve25519xsalsa20poly1305_tweet_VERSION "-"
#define crypto_box_curve25519xsalsa20poly1305 crypto_box_curve25519xsalsa20poly1305_tweet
#define crypto_box_curve25519xsalsa20poly1305_open crypto_box_curve25519xsalsa20poly1305_tweet_open
#define crypto_box_curve25519xsalsa20poly1305_keypair crypto_box_curve25519xsalsa20poly1305_tweet_keypair
#define crypto_box_curve25519xsalsa20poly1305_beforenm crypto_box_curve25519xsalsa20poly1305_tweet_beforenm
#define crypto_box_curve25519xsalsa20poly1305_afternm crypto_box_curve25519xsalsa20poly1305_tweet_afternm
#define crypto_box_curve25519xsalsa20poly1305_open_afternm crypto_box_curve25519xsalsa20poly1305_tweet_open_afternm
#define crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES crypto_box_curve25519xsalsa20poly1305_tweet_PUBLICKEYBYTES
#define crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES crypto_box_curve25519xsalsa20poly1305_tweet_SECRETKEYBYTES
#define crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES crypto_box_curve25519xsalsa20poly1305_tweet_BEFORENMBYTES
#define crypto_box_curve25519xsalsa20poly1305_NONCEBYTES crypto_box_curve25519xsalsa20poly1305_tweet_NONCEBYTES
#define crypto_box_curve25519xsalsa20poly1305_ZEROBYTES crypto_box_curve25519xsalsa20poly1305_tweet_ZEROBYTES
#define crypto_box_curve25519xsalsa20poly1305_BOXZEROBYTES crypto_box_curve25519xsalsa20poly1305_tweet_BOXZEROBYTES
#define crypto_box_curve25519xsalsa20poly1305_VERSION crypto_box_curve25519xsalsa20poly1305_tweet_VERSION
#define crypto_box_curve25519xsalsa20poly1305_IMPLEMENTATION "crypto_box/curve25519xsalsa20poly1305/tweet"
#define crypto_core_PRIMITIVE "salsa20"
#define crypto_core crypto_core_salsa20
#define crypto_core_OUTPUTBYTES crypto_core_salsa20_OUTPUTBYTES
#define crypto_core_INPUTBYTES crypto_core_salsa20_INPUTBYTES
#define crypto_core_KEYBYTES crypto_core_salsa20_KEYBYTES
#define crypto_core_CONSTBYTES crypto_core_salsa20_CONSTBYTES
#define crypto_core_IMPLEMENTATION crypto_core_salsa20_IMPLEMENTATION
#define crypto_core_VERSION crypto_core_salsa20_VERSION
#define crypto_core_salsa20_tweet_OUTPUTBYTES 64
#define crypto_core_salsa20_tweet_INPUTBYTES 16
#define crypto_core_salsa20_tweet_KEYBYTES 32
#define crypto_core_salsa20_tweet_CONSTBYTES 16
extern int crypto_core_salsa20_tweet(unsigned char *,const unsigned char *,const unsigned char *,const unsigned char *);
#define crypto_core_salsa20_tweet_VERSION "-"
#define crypto_core_salsa20 crypto_core_salsa20_tweet
#define crypto_core_salsa20_OUTPUTBYTES crypto_core_salsa20_tweet_OUTPUTBYTES
#define crypto_core_salsa20_INPUTBYTES crypto_core_salsa20_tweet_INPUTBYTES
#define crypto_core_salsa20_KEYBYTES crypto_core_salsa20_tweet_KEYBYTES
#define crypto_core_salsa20_CONSTBYTES crypto_core_salsa20_tweet_CONSTBYTES
#define crypto_core_salsa20_VERSION crypto_core_salsa20_tweet_VERSION
#define crypto_core_salsa20_IMPLEMENTATION "crypto_core/salsa20/tweet"
#define crypto_core_hsalsa20_tweet_OUTPUTBYTES 32
#define crypto_core_hsalsa20_tweet_INPUTBYTES 16
#define crypto_core_hsalsa20_tweet_KEYBYTES 32
#define crypto_core_hsalsa20_tweet_CONSTBYTES 16
extern int crypto_core_hsalsa20_tweet(unsigned char *,const unsigned char *,const unsigned char *,const unsigned char *);
#define crypto_core_hsalsa20_tweet_VERSION "-"
#define crypto_core_hsalsa20 crypto_core_hsalsa20_tweet
#define crypto_core_hsalsa20_OUTPUTBYTES crypto_core_hsalsa20_tweet_OUTPUTBYTES
#define crypto_core_hsalsa20_INPUTBYTES crypto_core_hsalsa20_tweet_INPUTBYTES
#define crypto_core_hsalsa20_KEYBYTES crypto_core_hsalsa20_tweet_KEYBYTES
#define crypto_core_hsalsa20_CONSTBYTES crypto_core_hsalsa20_tweet_CONSTBYTES
#define crypto_core_hsalsa20_VERSION crypto_core_hsalsa20_tweet_VERSION
#define crypto_core_hsalsa20_IMPLEMENTATION "crypto_core/hsalsa20/tweet"
#define crypto_hashblocks_PRIMITIVE "sha512"
#define crypto_hashblocks crypto_hashblocks_sha512
#define crypto_hashblocks_STATEBYTES crypto_hashblocks_sha512_STATEBYTES
#define crypto_hashblocks_BLOCKBYTES crypto_hashblocks_sha512_BLOCKBYTES
#define crypto_hashblocks_IMPLEMENTATION crypto_hashblocks_sha512_IMPLEMENTATION
#define crypto_hashblocks_VERSION crypto_hashblocks_sha512_VERSION
#define crypto_hashblocks_sha512_tweet_STATEBYTES 64
#define crypto_hashblocks_sha512_tweet_BLOCKBYTES 128
extern int crypto_hashblocks_sha512_tweet(unsigned char *,const unsigned char *,unsigned long long);
#define crypto_hashblocks_sha512_tweet_VERSION "-"
#define crypto_hashblocks_sha512 crypto_hashblocks_sha512_tweet
#define crypto_hashblocks_sha512_STATEBYTES crypto_hashblocks_sha512_tweet_STATEBYTES
#define crypto_hashblocks_sha512_BLOCKBYTES crypto_hashblocks_sha512_tweet_BLOCKBYTES
#define crypto_hashblocks_sha512_VERSION crypto_hashblocks_sha512_tweet_VERSION
#define crypto_hashblocks_sha512_IMPLEMENTATION "crypto_hashblocks/sha512/tweet"
#define crypto_hashblocks_sha256_tweet_STATEBYTES 32
#define crypto_hashblocks_sha256_tweet_BLOCKBYTES 64
extern int crypto_hashblocks_sha256_tweet(unsigned char *,const unsigned char *,unsigned long long);
#define crypto_hashblocks_sha256_tweet_VERSION "-"
#define crypto_hashblocks_sha256 crypto_hashblocks_sha256_tweet
#define crypto_hashblocks_sha256_STATEBYTES crypto_hashblocks_sha256_tweet_STATEBYTES
#define crypto_hashblocks_sha256_BLOCKBYTES crypto_hashblocks_sha256_tweet_BLOCKBYTES
#define crypto_hashblocks_sha256_VERSION crypto_hashblocks_sha256_tweet_VERSION
#define crypto_hashblocks_sha256_IMPLEMENTATION "crypto_hashblocks/sha256/tweet"
#define crypto_hash_PRIMITIVE "sha512"
#define crypto_hash crypto_hash_sha512
#define crypto_hash_BYTES crypto_hash_sha512_BYTES
#define crypto_hash_IMPLEMENTATION crypto_hash_sha512_IMPLEMENTATION
#define crypto_hash_VERSION crypto_hash_sha512_VERSION
#define crypto_hash_sha512_tweet_BYTES 64
extern int crypto_hash_sha512_tweet(unsigned char *,const unsigned char *,unsigned long long);
#define crypto_hash_sha512_tweet_VERSION "-"
#define crypto_hash_sha512 crypto_hash_sha512_tweet
#define crypto_hash_sha512_BYTES crypto_hash_sha512_tweet_BYTES
#define crypto_hash_sha512_VERSION crypto_hash_sha512_tweet_VERSION
#define crypto_hash_sha512_IMPLEMENTATION "crypto_hash/sha512/tweet"
#define crypto_hash_sha256_tweet_BYTES 32
extern int crypto_hash_sha256_tweet(unsigned char *,const unsigned char *,unsigned long long);
#define crypto_hash_sha256_tweet_VERSION "-"
#define crypto_hash_sha256 crypto_hash_sha256_tweet
#define crypto_hash_sha256_BYTES crypto_hash_sha256_tweet_BYTES
#define crypto_hash_sha256_VERSION crypto_hash_sha256_tweet_VERSION
#define crypto_hash_sha256_IMPLEMENTATION "crypto_hash/sha256/tweet"
#define crypto_onetimeauth_PRIMITIVE "poly1305"
#define crypto_onetimeauth crypto_onetimeauth_poly1305
#define crypto_onetimeauth_verify crypto_onetimeauth_poly1305_verify
#define crypto_onetimeauth_BYTES crypto_onetimeauth_poly1305_BYTES
#define crypto_onetimeauth_KEYBYTES crypto_onetimeauth_poly1305_KEYBYTES
#define crypto_onetimeauth_IMPLEMENTATION crypto_onetimeauth_poly1305_IMPLEMENTATION
#define crypto_onetimeauth_VERSION crypto_onetimeauth_poly1305_VERSION
#define crypto_onetimeauth_poly1305_tweet_BYTES 16
#define crypto_onetimeauth_poly1305_tweet_KEYBYTES 32
extern int crypto_onetimeauth_poly1305_tweet(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *);
extern int crypto_onetimeauth_poly1305_tweet_verify(const unsigned char *,const unsigned char *,unsigned long long,const unsigned char *);
#define crypto_onetimeauth_poly1305_tweet_VERSION "-"
#define crypto_onetimeauth_poly1305 crypto_onetimeauth_poly1305_tweet
#define crypto_onetimeauth_poly1305_verify crypto_onetimeauth_poly1305_tweet_verify
#define crypto_onetimeauth_poly1305_BYTES crypto_onetimeauth_poly1305_tweet_BYTES
#define crypto_onetimeauth_poly1305_KEYBYTES crypto_onetimeauth_poly1305_tweet_KEYBYTES
#define crypto_onetimeauth_poly1305_VERSION crypto_onetimeauth_poly1305_tweet_VERSION
#define crypto_onetimeauth_poly1305_IMPLEMENTATION "crypto_onetimeauth/poly1305/tweet"
#define crypto_scalarmult_PRIMITIVE "curve25519"
#define crypto_scalarmult crypto_scalarmult_curve25519
#define crypto_scalarmult_base crypto_scalarmult_curve25519_base
#define crypto_scalarmult_BYTES crypto_scalarmult_curve25519_BYTES
#define crypto_scalarmult_SCALARBYTES crypto_scalarmult_curve25519_SCALARBYTES
#define crypto_scalarmult_IMPLEMENTATION crypto_scalarmult_curve25519_IMPLEMENTATION
#define crypto_scalarmult_VERSION crypto_scalarmult_curve25519_VERSION
#define crypto_scalarmult_curve25519_tweet_BYTES 32
#define crypto_scalarmult_curve25519_tweet_SCALARBYTES 32
extern int crypto_scalarmult_curve25519_tweet(unsigned char *,const unsigned char *,const unsigned char *);
extern int crypto_scalarmult_curve25519_tweet_base(unsigned char *,const unsigned char *);
#define crypto_scalarmult_curve25519_tweet_VERSION "-"
#define crypto_scalarmult_curve25519 crypto_scalarmult_curve25519_tweet
#define crypto_scalarmult_curve25519_base crypto_scalarmult_curve25519_tweet_base
#define crypto_scalarmult_curve25519_BYTES crypto_scalarmult_curve25519_tweet_BYTES
#define crypto_scalarmult_curve25519_SCALARBYTES crypto_scalarmult_curve25519_tweet_SCALARBYTES
#define crypto_scalarmult_curve25519_VERSION crypto_scalarmult_curve25519_tweet_VERSION
#define crypto_scalarmult_curve25519_IMPLEMENTATION "crypto_scalarmult/curve25519/tweet"
#define crypto_secretbox_PRIMITIVE "xsalsa20poly1305"
#define crypto_secretbox crypto_secretbox_xsalsa20poly1305
#define crypto_secretbox_open crypto_secretbox_xsalsa20poly1305_open
#define crypto_secretbox_KEYBYTES crypto_secretbox_xsalsa20poly1305_KEYBYTES
#define crypto_secretbox_NONCEBYTES crypto_secretbox_xsalsa20poly1305_NONCEBYTES
#define crypto_secretbox_ZEROBYTES crypto_secretbox_xsalsa20poly1305_ZEROBYTES
#define crypto_secretbox_BOXZEROBYTES crypto_secretbox_xsalsa20poly1305_BOXZEROBYTES
#define crypto_secretbox_IMPLEMENTATION crypto_secretbox_xsalsa20poly1305_IMPLEMENTATION
#define crypto_secretbox_VERSION crypto_secretbox_xsalsa20poly1305_VERSION
#define crypto_secretbox_xsalsa20poly1305_tweet_KEYBYTES 32
#define crypto_secretbox_xsalsa20poly1305_tweet_NONCEBYTES 24
#define crypto_secretbox_xsalsa20poly1305_tweet_ZEROBYTES 32
#define crypto_secretbox_xsalsa20poly1305_tweet_BOXZEROBYTES 16
extern int crypto_secretbox_xsalsa20poly1305_tweet(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *);
extern int crypto_secretbox_xsalsa20poly1305_tweet_open(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *);
#define crypto_secretbox_xsalsa20poly1305_tweet_VERSION "-"
#define crypto_secretbox_xsalsa20poly1305 crypto_secretbox_xsalsa20poly1305_tweet
#define crypto_secretbox_xsalsa20poly1305_open crypto_secretbox_xsalsa20poly1305_tweet_open
#define crypto_secretbox_xsalsa20poly1305_KEYBYTES crypto_secretbox_xsalsa20poly1305_tweet_KEYBYTES
#define crypto_secretbox_xsalsa20poly1305_NONCEBYTES crypto_secretbox_xsalsa20poly1305_tweet_NONCEBYTES
#define crypto_secretbox_xsalsa20poly1305_ZEROBYTES crypto_secretbox_xsalsa20poly1305_tweet_ZEROBYTES
#define crypto_secretbox_xsalsa20poly1305_BOXZEROBYTES crypto_secretbox_xsalsa20poly1305_tweet_BOXZEROBYTES
#define crypto_secretbox_xsalsa20poly1305_VERSION crypto_secretbox_xsalsa20poly1305_tweet_VERSION
#define crypto_secretbox_xsalsa20poly1305_IMPLEMENTATION "crypto_secretbox/xsalsa20poly1305/tweet"
#define crypto_sign_PRIMITIVE "ed25519"
#define crypto_sign crypto_sign_ed25519
#define crypto_sign_open crypto_sign_ed25519_open
#define crypto_sign_keypair crypto_sign_ed25519_keypair
#define crypto_sign_BYTES crypto_sign_ed25519_BYTES
#define crypto_sign_PUBLICKEYBYTES crypto_sign_ed25519_PUBLICKEYBYTES
#define crypto_sign_SECRETKEYBYTES crypto_sign_ed25519_SECRETKEYBYTES
#define crypto_sign_IMPLEMENTATION crypto_sign_ed25519_IMPLEMENTATION
#define crypto_sign_VERSION crypto_sign_ed25519_VERSION
#define crypto_sign_ed25519_tweet_BYTES 64
#define crypto_sign_ed25519_tweet_PUBLICKEYBYTES 32
#define crypto_sign_ed25519_tweet_SECRETKEYBYTES 64
extern int crypto_sign_ed25519_tweet(unsigned char *,unsigned long long *,const unsigned char *,unsigned long long,const unsigned char *);
extern int crypto_sign_ed25519_tweet_open(unsigned char *,unsigned long long *,const unsigned char *,unsigned long long,const unsigned char *);
extern int crypto_sign_ed25519_tweet_keypair(unsigned char *,unsigned char *);
#define crypto_sign_ed25519_tweet_VERSION "-"
#define crypto_sign_ed25519 crypto_sign_ed25519_tweet
#define crypto_sign_ed25519_open crypto_sign_ed25519_tweet_open
#define crypto_sign_ed25519_keypair crypto_sign_ed25519_tweet_keypair
#define crypto_sign_ed25519_BYTES crypto_sign_ed25519_tweet_BYTES
#define crypto_sign_ed25519_PUBLICKEYBYTES crypto_sign_ed25519_tweet_PUBLICKEYBYTES
#define crypto_sign_ed25519_SECRETKEYBYTES crypto_sign_ed25519_tweet_SECRETKEYBYTES
#define crypto_sign_ed25519_VERSION crypto_sign_ed25519_tweet_VERSION
#define crypto_sign_ed25519_IMPLEMENTATION "crypto_sign/ed25519/tweet"
#define crypto_stream_PRIMITIVE "xsalsa20"
#define crypto_stream crypto_stream_xsalsa20
#define crypto_stream_xor crypto_stream_xsalsa20_xor
#define crypto_stream_KEYBYTES crypto_stream_xsalsa20_KEYBYTES
#define crypto_stream_NONCEBYTES crypto_stream_xsalsa20_NONCEBYTES
#define crypto_stream_IMPLEMENTATION crypto_stream_xsalsa20_IMPLEMENTATION
#define crypto_stream_VERSION crypto_stream_xsalsa20_VERSION
#define crypto_stream_xsalsa20_tweet_KEYBYTES 32
#define crypto_stream_xsalsa20_tweet_NONCEBYTES 24
extern int crypto_stream_xsalsa20_tweet(unsigned char *,unsigned long long,const unsigned char *,const unsigned char *);
extern int crypto_stream_xsalsa20_tweet_xor(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *);
#define crypto_stream_xsalsa20_tweet_VERSION "-"
#define crypto_stream_xsalsa20 crypto_stream_xsalsa20_tweet
#define crypto_stream_xsalsa20_xor crypto_stream_xsalsa20_tweet_xor
#define crypto_stream_xsalsa20_KEYBYTES crypto_stream_xsalsa20_tweet_KEYBYTES
#define crypto_stream_xsalsa20_NONCEBYTES crypto_stream_xsalsa20_tweet_NONCEBYTES
#define crypto_stream_xsalsa20_VERSION crypto_stream_xsalsa20_tweet_VERSION
#define crypto_stream_xsalsa20_IMPLEMENTATION "crypto_stream/xsalsa20/tweet"
#define crypto_stream_salsa20_tweet_KEYBYTES 32
#define crypto_stream_salsa20_tweet_NONCEBYTES 8
extern int crypto_stream_salsa20_tweet(unsigned char *,unsigned long long,const unsigned char *,const unsigned char *);
extern int crypto_stream_salsa20_tweet_xor(unsigned char *,const unsigned char *,unsigned long long,const unsigned char *,const unsigned char *);
#define crypto_stream_salsa20_tweet_VERSION "-"
#define crypto_stream_salsa20 crypto_stream_salsa20_tweet
#define crypto_stream_salsa20_xor crypto_stream_salsa20_tweet_xor
#define crypto_stream_salsa20_KEYBYTES crypto_stream_salsa20_tweet_KEYBYTES
#define crypto_stream_salsa20_NONCEBYTES crypto_stream_salsa20_tweet_NONCEBYTES
#define crypto_stream_salsa20_VERSION crypto_stream_salsa20_tweet_VERSION
#define crypto_stream_salsa20_IMPLEMENTATION "crypto_stream/salsa20/tweet"
#define crypto_verify_PRIMITIVE "16"
#define crypto_verify crypto_verify_16
#define crypto_verify_BYTES crypto_verify_16_BYTES
#define crypto_verify_IMPLEMENTATION crypto_verify_16_IMPLEMENTATION
#define crypto_verify_VERSION crypto_verify_16_VERSION
#define crypto_verify_16_tweet_BYTES 16
extern int crypto_verify_16_tweet(const unsigned char *,const unsigned char *);
#define crypto_verify_16_tweet_VERSION "-"
#define crypto_verify_16 crypto_verify_16_tweet
#define crypto_verify_16_BYTES crypto_verify_16_tweet_BYTES
#define crypto_verify_16_VERSION crypto_verify_16_tweet_VERSION
#define crypto_verify_16_IMPLEMENTATION "crypto_verify/16/tweet"
#define crypto_verify_32_tweet_BYTES 32
extern int crypto_verify_32_tweet(const unsigned char *,const unsigned char *);
#define crypto_verify_32_tweet_VERSION "-"
#define crypto_verify_32 crypto_verify_32_tweet
#define crypto_verify_32_BYTES crypto_verify_32_tweet_BYTES
#define crypto_verify_32_VERSION crypto_verify_32_tweet_VERSION
#define crypto_verify_32_IMPLEMENTATION "crypto_verify/32/tweet"
#endif

View File

@@ -0,0 +1,18 @@
--dakjqwmnejadhasdkljkaeiasndansdahjdhjasd
Content-Type: text/plain
Please open the following link in your webbrowser to confirm your new WoW account:
<insert-url>
--dakjqwmnejadhasdkljkaeiasndansdahjdhjasd
Content-Type: text/html
<html>
<head>
<title>WoW Registration Confirmation</title>
</head>
<body>Please click the following link to confirm your new WoW account:<br>
<a href="<insert-url>"><insert-url></a>
</body></html>
--dakjqwmnejadhasdkljkaeiasndansdahjdhjasd--

View File

@@ -0,0 +1,18 @@
--dakjqwmnejadhasdkljkaeiasndansdahjdhjasd
Content-Type: text/plain
Please open the following link in your webbrowser to confirm the new password for your WoW account:
<insert-url>
--dakjqwmnejadhasdkljkaeiasndansdahjdhjasd
Content-Type: text/html
<html>
<head>
<title>WoW Password Reset Confirmation</title>
</head>
<body>Please click the following link to confirm the new password for your WoW account:<br>
<a href="<insert-url>"><insert-url></a>
</body></html>
--dakjqwmnejadhasdkljkaeiasndansdahjdhjasd--

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,18 @@
--dakjqwmnejadhasdkljkaeiasndansdahjdhjasd
Content-Type: text/plain
Please open the following link in your webbrowser to continue upgrading your WoW account:
<insert-url>
--dakjqwmnejadhasdkljkaeiasndansdahjdhjasd
Content-Type: text/html
<html>
<head>
<title>WoW Account Upgrade Email Validation</title>
</head>
<body>Please click the following link to continue upgrading your WoW account:<br>
<a href="<insert-url>"><insert-url></a>
</body></html>
--dakjqwmnejadhasdkljkaeiasndansdahjdhjasd--

View File

@@ -0,0 +1,171 @@
###############################################
# Trinity Core Auth Server configuration file #
###############################################
[webapi]
###################################################################################################
# SECTION INDEX
#
# EXAMPLE CONFIG
# AUTH SERVER SETTINGS
# MYSQL SETTINGS
#
###################################################################################################
###################################################################################################
# EXAMPLE CONFIG
#
# Variable
# Description: Brief description what the variable is doing.
# Important: Annotation for important things about this variable.
# Example: "Example, i.e. if the value is a string"
# Default: 10 - (Enabled|Comment|Variable name in case of grouped config options)
# 0 - (Disabled|Comment|Variable name in case of grouped config options)
#
# Note to developers:
# - Copy this example to keep the formatting.
# - Line breaks should be at column 100.
###################################################################################################
###################################################################################################
# AUTH SERVER SETTINGS
#
# Port
# Description: TCP port to reach the webapi server.
# Default: 8090
Port = 8090
#
#
# BindIP
# Description: Bind webapi server to IP/hostname
# Default: "127.0.0.1" - (Bind to localhost)
BindIP = "127.0.0.1"
#
###################################################################################################
###################################################################################################
# MYSQL SETTINGS
#
# LoginDatabaseInfo
# Description: Database connection settings for the realm server.
# Example: "hostname;port;username;password;database"
# ".;somenumber;username;password;database" - (Use named pipes on Windows
# "enable-named-pipe" to [mysqld]
# section my.ini)
# ".;/path/to/unix_socket;username;password;database" - (use Unix sockets on
# Unix/Linux)
# Default: "127.0.0.1;3306;trinity;trinity;auth"
LoginDatabaseInfo = "127.0.0.1;3306;trinity;trinity;auth"
#
###################################################################################################
###################################################################################################
# SMTP SERVER SETTINGS
#
# Port
# Description: TCP port to reach the webapi server.
# Default: 25
SMTPPort = 25
#
#
# BindIP
# Description: Bind webapi server to IP/hostname
# Default: "127.0.0.1" - (Bind to localhost)
SMTPIP = "127.0.0.1"
SMTPUser = "user"
SMTPPassword = "password"
SMTPFromAddress = "no-reply@wow.com"
SMTPFromName = "WoW"
SMTPMailRegistrationSubject = "WoW - Registration Confirmation"
SMTPMailResetSubject = "WoW - Password Reset Confirmation"
SMTPMailValidationSubject = "WoW - Account Upgrade Email Validation"
SMTPMailConfirmationSubject = "WoW - Account Upgrade Confirmation"
SMTPReturnDomain = "https://wow.com"
#
###################################################################################################
###################################################################################################
# NEWSLETTER SETTINGS
NewsLetterUnsubDomain = "https://unsubscribe.wow.com/unsubscribe/"
NewsLetterSubject = "WoW Subject"
NewsLetterMailForUnsubscribe = "unsubscribe@wow.com"
NewsLetterSecondsBetweenMails = 5
#
###################################################################################################
###################################################################################################
# IFRAME SETTINGS
RefUrlHeader = <html><head></head><body><div>
RefUrlFooter = </div></body></html>
#
###################################################################################################
###################################################################################################
# REAL IP SETTINGS
# IpFromHeader = X-Real-IP
#
###################################################################################################
###################################################################################################
# VOTE SETTINGS
WebsiteName1 = TopG
CallbackKeyName1 = p_resp
CallbackHostname1 = monitor.topg.org
CallbackUrl1 = /callback/topg-vote/api
VoteUrl1 = https://topg.org/CATEGORY/in-SITEID-
VoteToken1 = 1
VoteTokensGiven1 = 2
WebsiteName2 = XtremeTop100
CallbackKeyName2 = custom
CallbackHostname2 = xtremetop100.com
CallbackUrl2 = /callback/xtremetop100-vote/api
VoteUrl2 = https://www.xtremetop100.com/in.php?site=SITEID&postback=
VoteToken2 = 1
VoteTokensGiven2 = 0
WebisteName3 = ArenaTop100
CallbackKeyName3 = userid
CallbackIps3 = 0.0.0.0
CallbackUrl3 = /callback/arenatop100-vote/api
VoteUrl3 = https://www.arena-top100.com/index.php?a=in&u=ARENA-TOP100-USERNAME&id=
CheckKeyName3 = voted
CheckKeyValue3 = 1
VoteToken3 = 1
VoteTokensGiven3 = 1
WebisteName4 = GamingTop100
CallbackKeyName4 = userid
CallbackHostname4 = gamingtop100.net
CallbackUrl4 = /callback/gamingtop100-vote/api
CallbackIdOnlyDigits4 = 1
VoteUrl4 = http://gamingtop100.net/in-SITEID-
VoteToken4 = 1
VoteTokensGiven4 = 1