text:
/**
 * @file llfontgl.cpp
 * @brief Wrapper around FreeType
 *
 * $LicenseInfo:firstyear=2001&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2010, Linden Research, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * version 2.1 of the License only.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */

#include "linden_common.h"

#include "llfontgl.h"

// Linden library includes
#include "llfasttimer.h"
#include "llfontfreetype.h"
#include "llfontbitmapcache.h"
#include "llfontregistry.h"
#include "llgl.h"
#include "llimagegl.h"
#include "llrender.h"
#include "llstl.h"
#include "v4color.h"
#include "lltexture.h"
#include "lldir.h"
#include "llstring.h"

// Third party library includes
#include <boost/tokenizer.hpp>

#if LL_WINDOWS
#include <Shlobj.h>
#include <Knownfolders.h>
#include <Objbase.h>
#endif // LL_WINDOWS

const S32 BOLD_OFFSET = 1;

// static class members
F32 LLFontGL::sVertDPI = 96.f;
F32 LLFontGL::sHorizDPI = 96.f;
F32 LLFontGL::sScaleX = 1.f;
F32 LLFontGL::sScaleY = 1.f;
BOOL LLFontGL::sDisplayFont = TRUE ;
std::string LLFontGL::sAppDir;

LLColor4 LLFontGL::sShadowColor(0.f, 0.f, 0.f, 1.f);
LLFontRegistry* LLFontGL::sFontRegistry = NULL;

LLCoordGL LLFontGL::sCurOrigin;
F32 LLFontGL::sCurDepth;
std::vector<std::pair<LLCoordGL, F32> > LLFontGL::sOriginStack;

const F32 PAD_UVY = 0.5f; // half of vertical padding between glyphs in the glyph texture
const F32 DROP_SHADOW_SOFT_STRENGTH = 0.3f;

LLFontGL::LLFontGL()
{
}

LLFontGL::~LLFontGL()
{
}

void LLFontGL::reset()
{
	mFontFreetype->reset(sVertDPI, sHorizDPI);
}

void LLFontGL::destroyGL()
{
	mFontFreetype->destroyGL();
}

BOOL LLFontGL::loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, S32 components, BOOL is_fallback, S32 face_n)
{
	if(mFontFreetype == reinterpret_cast<LLFontFreetype*>(NULL))
	{
		mFontFreetype = new LLFontFreetype;
	}

	return mFontFreetype->loadFace(filename, point_size, vert_dpi, horz_dpi, components, is_fallback, face_n);
}

S32 LLFontGL::getNumFaces(const std::string& filename)
{
	if (mFontFreetype == reinterpret_cast<LLFontFreetype*>(NULL))
	{
		mFontFreetype = new LLFontFreetype;
	}

	return mFontFreetype->getNumFaces(filename);
}

static LLTrace::BlockTimerStatHandle FTM_RENDER_FONTS("Fonts");

S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, const LLRect& rect, const LLColor4 &color, HAlign halign, VAlign valign, U8 style,
    ShadowType shadow, S32 max_chars, F32* right_x, BOOL use_ellipses) const
{
    LLRectf rect_float(rect.mLeft, rect.mTop, rect.mRight, rect.mBottom);
    return render(wstr, begin_offset, rect_float, color, halign, valign, style, shadow, max_chars, right_x, use_ellipses);
}

S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, const LLRectf& rect, const LLColor4 &color, HAlign halign, VAlign valign, U8 style,
					 ShadowType shadow, S32 max_chars, F32* right_x, BOOL use_ellipses) const
{
	F32 x = rect.mLeft;
	F32 y = 0.f;

	switch(valign)
	{
	case TOP:
		y = rect.mTop;
		break;
	case VCENTER:
		y = rect.getCenterY();
		break;
	case BASELINE:
	case BOTTOM:
		y = rect.mBottom;
		break;
	default:
		y = rect.mBottom;
		break;
	}
	return render(wstr, begin_offset, x, y, color, halign, valign, style, shadow, max_chars, rect.getWidth(), right_x, use_ellipses);
}

S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style,
					 ShadowType shadow, S32 max_chars, S32 max_pixels, F32* right_x, BOOL use_ellipses) const
{
	LL_RECORD_BLOCK_TIME(FTM_RENDER_FONTS);

	if(!sDisplayFont) //do not display texts
	{
		return wstr.length() ;
	}

	if (wstr.empty())
	{
		return 0;
	}

	gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);

	S32 scaled_max_pixels = max_pixels == S32_MAX ? S32_MAX : llceil((F32)max_pixels * sScaleX);

	// determine which style flags need to be added programmatically by stripping off the
	// style bits that are drawn by the underlying Freetype font
	U8 style_to_add = (style | mFontDescriptor.getStyle()) & ~mFontFreetype->getStyle();

	F32 drop_shadow_strength = 0.f;
	if (shadow != NO_SHADOW)
	{
		F32 luminance;
		color.calcHSL(NULL, NULL, &luminance);
		drop_shadow_strength = clamp_rescale(luminance, 0.35f, 0.6f, 0.f, 1.f);
		if (luminance < 0.35f)
		{
			shadow = NO_SHADOW;
		}
	}

	gGL.pushUIMatrix();

	gGL.loadUIIdentity();

	LLVector2 origin(floorf(sCurOrigin.mX*sScaleX), floorf(sCurOrigin.mY*sScaleY));

	// Depth translation, so that floating text appears 'in-world'
	// and is correctly occluded.
	gGL.translatef(0.f,0.f,sCurDepth);

	S32 chars_drawn = 0;
	S32 i;
	S32 length;

	if (-1 == max_chars)
	{
		length = (S32)wstr.length() - begin_offset;
	}
	else
	{
		length = llmin((S32)wstr.length() - begin_offset, max_chars );
	}

	F32 cur_x, cur_y, cur_render_x, cur_render_y;

 	// Not guaranteed to be set correctly
	gGL.setSceneBlendType(LLRender::BT_ALPHA);

	cur_x = ((F32)x * sScaleX) + origin.mV[VX];
	cur_y = ((F32)y * sScaleY) + origin.mV[VY];

	// Offset y by vertical alignment.
	// use unscaled font metrics here
	switch (valign)
	{
	case TOP:
		cur_y -= llceil(mFontFreetype->getAscenderHeight());
		break;
	case BOTTOM:
		cur_y += llceil(mFontFreetype->getDescenderHeight());
		break;
	case VCENTER:
		cur_y -= llceil((llceil(mFontFreetype->getAscenderHeight()) - llceil(mFontFreetype->getDescenderHeight())) / 2.f);
		break;
	case BASELINE:
		// Baseline, do nothing.
		break;
	default:
		break;
	}

	switch (halign)
	{
	case LEFT:
		break;
	case RIGHT:
	  	cur_x -= llmin(scaled_max_pixels, ll_round(getWidthF32(wstr.c_str(), begin_offset, length) * sScaleX));
		break;
	case HCENTER:
	    cur_x -= llmin(scaled_max_pixels, ll_round(getWidthF32(wstr.c_str(), begin_offset, length) * sScaleX)) / 2;
		break;
	default:
		break;
	}

	cur_render_y = cur_y;
	cur_render_x = cur_x;

	F32 start_x = (F32)ll_round(cur_x);

	const LLFontBitmapCache* font_bitmap_cache = mFontFreetype->getFontBitmapCache();

	F32 inv_width = 1.f / font_bitmap_cache->getBitmapWidth();
	F32 inv_height = 1.f / font_bitmap_cache->getBitmapHeight();

	const S32 LAST_CHARACTER = LLFontFreetype::LAST_CHAR_FULL;

	BOOL draw_ellipses = FALSE;
	if (use_ellipses)
	{
		// check for too long of a string
		S32 string_width = ll_round(getWidthF32(wstr.c_str(), begin_offset, max_chars) * sScaleX);
		if (string_width > scaled_max_pixels)
		{
			// use four dots for ellipsis width to generate padding
			const LLWString dots(utf8str_to_wstring(std::string("....")));
			scaled_max_pixels = llmax(0, scaled_max_pixels - ll_round(getWidthF32(dots.c_str())));
			draw_ellipses = TRUE;
		}
	}

	const LLFontGlyphInfo* next_glyph = NULL;

	const S32 GLYPH_BATCH_SIZE = 30;
	// <FS:Ansariel> Remove QUADS rendering mode
	//LLVector3 vertices[GLYPH_BATCH_SIZE * 4];
	//LLVector2 uvs[GLYPH_BATCH_SIZE * 4];
	//LLColor4U colors[GLYPH_BATCH_SIZE * 4];
	LLVector3 vertices[GLYPH_BATCH_SIZE * 6];
	LLVector2 uvs[GLYPH_BATCH_SIZE * 6];
	LLColor4U colors[GLYPH_BATCH_SIZE * 6];
	// </FS:Ansariel>

	LLColor4U text_color(color);

	S32 bitmap_num = -1;
	S32 glyph_count = 0;
	for (i = begin_offset; i < begin_offset + length; i++)
	{
		llwchar wch = wstr[i];

		const LLFontGlyphInfo* fgi = next_glyph;
		next_glyph = NULL;
		if(!fgi)
		{
			fgi = mFontFreetype->getGlyphInfo(wch);
		}
		if (!fgi)
		{
			LL_ERRS() << "Missing Glyph Info" << LL_ENDL;
			break;
		}
		// Per-glyph bitmap texture.
		S32 next_bitmap_num = fgi->mBitmapNum;
		if (next_bitmap_num != bitmap_num)
		{
			// Actually draw the queued glyphs before switching their texture;
			// otherwise the queued glyphs will be taken from wrong textures.
			if (glyph_count > 0)
			{
				// <FS:Ansariel> Remove QUADS rendering mode
				//gGL.begin(LLRender::QUADS);
				//{
				//	gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 4);
				//}
				//gGL.end();
				gGL.begin(LLRender::TRIANGLES);
				{
					gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 6);
				}
				gGL.end();
				// </FS:Ansariel>
				glyph_count = 0;
			}

			bitmap_num = next_bitmap_num;
			LLImageGL *font_image = font_bitmap_cache->getImageGL(bitmap_num);
			gGL.getTexUnit(0)->bind(font_image);
		}

		if ((start_x + scaled_max_pixels) < (cur_x + fgi->mXBearing + fgi->mWidth))
		{
			// Not enough room for this character.
			break;
		}

		// Draw the text at the appropriate location
		//Specify vertices and texture coordinates
		LLRectf uv_rect((fgi->mXBitmapOffset) * inv_width,
				(fgi->mYBitmapOffset + fgi->mHeight + PAD_UVY) * inv_height,
				(fgi->mXBitmapOffset + fgi->mWidth) * inv_width,
				(fgi->mYBitmapOffset - PAD_UVY) * inv_height);
		// snap glyph origin to whole screen pixel
		LLRectf screen_rect((F32)ll_round(cur_render_x + (F32)fgi->mXBearing),
				    (F32)ll_round(cur_render_y + (F32)fgi->mYBearing),
				    (F32)ll_round(cur_render_x + (F32)fgi->mXBearing) + (F32)fgi->mWidth,
				    (F32)ll_round(cur_render_y + (F32)fgi->mYBearing) - (F32)fgi->mHeight);

		if (glyph_count >= GLYPH_BATCH_SIZE)
		{
			// <FS:Ansariel> Remove QUADS rendering mode
			//gGL.begin(LLRender::QUADS);
			//{
			//	gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 4);
			//}
			//gGL.end();
			gGL.begin(LLRender::TRIANGLES);
			{
				gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 6);
			}
			gGL.end();
			// </FS:Ansariel>

			glyph_count = 0;
		}

		drawGlyph(glyph_count, vertices, uvs, colors, screen_rect, uv_rect, text_color, style_to_add, shadow, drop_shadow_strength);

		chars_drawn++;
		cur_x += fgi->mXAdvance;
		cur_y += fgi->mYAdvance;

		llwchar next_char = wstr[i+1];
		if (next_char && (next_char < LAST_CHARACTER))
		{
			// Kern this puppy.
			next_glyph = mFontFreetype->getGlyphInfo(next_char);
			cur_x += mFontFreetype->getXKerning(fgi, next_glyph);
		}

		// Round after kerning.
		// Must do this to cur_x, not just to cur_render_x, otherwise you
		// will squish sub-pixel kerned characters too close together.
		// For example, "CCCCC" looks bad.
		cur_x = (F32)ll_round(cur_x);
		//cur_y = (F32)ll_round(cur_y);

		cur_render_x = cur_x;
		cur_render_y = cur_y;
	}

	// <FS:Ansariel> Remove QUADS rendering mode
	//gGL.begin(LLRender::QUADS);
	//{
	//	gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 4);
	//}
	//gGL.end();
	gGL.begin(LLRender::TRIANGLES);
	{
		gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 6);
	}
	gGL.end();
	// </FS:Ansariel>

	if (right_x)
	{
		*right_x = (cur_x - origin.mV[VX]) / sScaleX;
	}

	//FIXME: add underline as glyph?
	if (style_to_add & UNDERLINE)
	{
		F32 descender = (F32)llfloor(mFontFreetype->getDescenderHeight());

		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
		gGL.begin(LLRender::LINES);
		gGL.vertex2f(start_x, cur_y - descender);
		gGL.vertex2f(cur_x, cur_y - descender);
		gGL.end();
	}

	if (draw_ellipses)
	{

		// recursively render ellipses at end of string
		// we've already reserved enough room
		gGL.pushUIMatrix();
		renderUTF8(std::string("..."),
				0,
				(cur_x - origin.mV[VX]) / sScaleX, (F32)y,
				color,
				LEFT, valign,
				style_to_add,
				shadow,
				S32_MAX, max_pixels,
				right_x,
				FALSE);
		gGL.popUIMatrix();
	}

	gGL.popUIMatrix();

	return chars_drawn;
}

S32 LLFontGL::render(const LLWString &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color) const
{
	return render(text, begin_offset, x, y, color, LEFT, BASELINE, NORMAL, NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE);
}

S32 LLFontGL::renderUTF8(const std::string &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign,  VAlign valign, U8 style, ShadowType shadow, S32 max_chars, S32 max_pixels,  F32* right_x, BOOL use_ellipses) const
{
	return render(utf8str_to_wstring(text), begin_offset, x, y, color, halign, valign, style, shadow, max_chars, max_pixels, right_x, use_ellipses);
}

S32 LLFontGL::renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color) const
{
	return renderUTF8(text, begin_offset, (F32)x, (F32)y, color, LEFT, BASELINE, NORMAL, NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE);
}

S32 LLFontGL::renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, ShadowType shadow) const
{
	return renderUTF8(text, begin_offset, (F32)x, (F32)y, color, halign, valign, style, shadow, S32_MAX, S32_MAX, NULL, FALSE);
}

// font metrics - override for LLFontFreetype that returns units of virtual pixels
F32 LLFontGL::getAscenderHeight() const
{
	return mFontFreetype->getAscenderHeight() / sScaleY;
}

F32 LLFontGL::getDescenderHeight() const
{
	return mFontFreetype->getDescenderHeight() / sScaleY;
}

S32 LLFontGL::getLineHeight() const
{
	return llceil(mFontFreetype->getAscenderHeight() / sScaleY) + llceil(mFontFreetype->getDescenderHeight() / sScaleY);
}

S32 LLFontGL::getWidth(const std::string& utf8text) const
{
	LLWString wtext = utf8str_to_wstring(utf8text);
	return getWidth(wtext.c_str(), 0, S32_MAX);
}

S32 LLFontGL::getWidth(const llwchar* wchars) const
{
	return getWidth(wchars, 0, S32_MAX);
}

S32 LLFontGL::getWidth(const std::string& utf8text, S32 begin_offset, S32 max_chars) const
{
	LLWString wtext = utf8str_to_wstring(utf8text);
	return getWidth(wtext.c_str(), begin_offset, max_chars);
}

S32 LLFontGL::getWidth(const llwchar* wchars, S32 begin_offset, S32 max_chars) const
{
	F32 width = getWidthF32(wchars, begin_offset, max_chars);
	return ll_round(width);
}

F32 LLFontGL::getWidthF32(const std::string& utf8text) const
{
	LLWString wtext = utf8str_to_wstring(utf8text);
	return getWidthF32(wtext.c_str(), 0, S32_MAX);
}

F32 LLFontGL::getWidthF32(const llwchar* wchars) const
{
	return getWidthF32(wchars, 0, S32_MAX);
}

F32 LLFontGL::getWidthF32(const std::string& utf8text, S32 begin_offset, S32 max_chars ) const
{
	LLWString wtext = utf8str_to_wstring(utf8text);
	return getWidthF32(wtext.c_str(), begin_offset, max_chars);
}

F32 LLFontGL::getWidthF32(const llwchar* wchars, S32 begin_offset, S32 max_chars) const
{
	const S32 LAST_CHARACTER = LLFontFreetype::LAST_CHAR_FULL;

	F32 cur_x = 0;
	const S32 max_index = begin_offset + max_chars;

	const LLFontGlyphInfo* next_glyph = NULL;

	F32 width_padding = 0.f;
	for (S32 i = begin_offset; i < max_index && wchars[i] != 0; i++)
	{
		llwchar wch = wchars[i];

		const LLFontGlyphInfo* fgi = next_glyph;
		next_glyph = NULL;
		if(!fgi)
		{
			fgi = mFontFreetype->getGlyphInfo(wch);
		}

		F32 advance = mFontFreetype->getXAdvance(fgi);

		// for the last character we want to measure the greater of its width and xadvance values
		// so keep track of the difference between these values for the each character we measure
		// so we can fix things up at the end
		width_padding = llmax(	0.f,											// always use positive padding amount
								width_padding - advance,						// previous padding left over after advance of current character
								(F32)(fgi->mWidth + fgi->mXBearing) - advance);	// difference between width of this character and advance to next character

		cur_x += advance;
		llwchar next_char = wchars[i+1];

		if (((i + 1) < begin_offset + max_chars)
			&& next_char
			&& (next_char < LAST_CHARACTER))
		{
			// Kern this puppy.
			next_glyph = mFontFreetype->getGlyphInfo(next_char);
			cur_x += mFontFreetype->getXKerning(fgi, next_glyph);
		}
		// Round after kerning.
		cur_x = (F32)ll_round(cur_x);
	}

	// add in extra pixels for last character's width past its xadvance
	cur_x += width_padding;

	return cur_x / sScaleX;
}

// Returns the max number of complete characters from text (up to max_chars) that can be drawn in max_pixels
S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_chars, EWordWrapStyle end_on_word_boundary) const
{
	if (!wchars || !wchars[0] || max_chars == 0)
	{
		return 0;
	}

	llassert(max_pixels >= 0.f);
	llassert(max_chars >= 0);

	BOOL clip = FALSE;
	F32 cur_x = 0;

	S32 start_of_last_word = 0;
	BOOL in_word = FALSE;

	// avoid S32 overflow when max_pixels == S32_MAX by staying in floating point
	F32 scaled_max_pixels =	max_pixels * sScaleX;
	F32 width_padding = 0.f;

	LLFontGlyphInfo* next_glyph = NULL;

	S32 i;
	for (i=0; (i < max_chars); i++)
	{
		llwchar wch = wchars[i];

		if(wch == 0)
		{
			// Null terminator.  We're done.
			break;
		}

		if (in_word)
		{
			if (iswspace(wch))
			{
				if(wch !=(0x00A0))
				{
					in_word = FALSE;
				}
			}
			if (iswindividual(wch))
			{
				if (iswpunct(wchars[i+1]))
				{
					in_word=TRUE;
				}
				else
				{
					in_word=FALSE;
					start_of_last_word = i;
				}
			}
		}
		else
		{
			start_of_last_word = i;
			if (!iswspace(wch)||!iswindividual(wch))
			{
				in_word = TRUE;
			}
		}

		LLFontGlyphInfo* fgi = next_glyph;
		next_glyph = NULL;
		if(!fgi)
		{
			fgi = mFontFreetype->getGlyphInfo(wch);

			if (NULL == fgi)
			{
				return 0;
			}
		}

		// account for glyphs that run beyond the starting point for the next glyphs
		width_padding = llmax(	0.f,													// always use positive padding amount
								width_padding - fgi->mXAdvance,							// previous padding left over after advance of current character
								(F32)(fgi->mWidth + fgi->mXBearing) - fgi->mXAdvance);	// difference between width of this character and advance to next character

		cur_x += fgi->mXAdvance;

		// clip if current character runs past scaled_max_pixels (using width_padding)
		if (scaled_max_pixels < cur_x + width_padding)
		{
			clip = TRUE;
			break;
		}

		if (((i+1) < max_chars) && wchars[i+1])
		{
			// Kern this puppy.
			next_glyph = mFontFreetype->getGlyphInfo(wchars[i+1]);
			cur_x += mFontFreetype->getXKerning(fgi, next_glyph);
		}

		// Round after kerning.
		cur_x = (F32)ll_round(cur_x);
	}

	if( clip )
	{
		switch (end_on_word_boundary)
		{
		case ONLY_WORD_BOUNDARIES:
			i = start_of_last_word;
			break;
		case WORD_BOUNDARY_IF_POSSIBLE:
			if (start_of_last_word != 0)
			{
				i = start_of_last_word;
			}
			break;
		default:
		case ANYWHERE:
			// do nothing
			break;
		}
	}
	return i;
}

S32	LLFontGL::firstDrawableChar(const llwchar* wchars, F32 max_pixels, S32 text_len, S32 start_pos, S32 max_chars) const
{
	if (!wchars || !wchars[0] || max_chars == 0)
	{
		return 0;
	}

	F32 total_width = 0.0;
	S32 drawable_chars = 0;

	F32 scaled_max_pixels =	max_pixels * sScaleX;

	S32 start = llmin(start_pos, text_len - 1);
	for (S32 i = start; i >= 0; i--)
	{
		llwchar wch = wchars[i];

		const LLFontGlyphInfo* fgi= mFontFreetype->getGlyphInfo(wch);

		// last character uses character width, since the whole character needs to be visible
		// other characters just use advance
		F32 width = (i == start)
			? (F32)(fgi->mWidth + fgi->mXBearing)  	// use actual width for last character
			: fgi->mXAdvance;						// use advance for all other characters

		if( scaled_max_pixels < (total_width + width) )
		{
			break;
		}

		total_width += width;
		drawable_chars++;

		if( max_chars >= 0 && drawable_chars >= max_chars )
		{
			break;
		}

		if ( i > 0 )
		{
			// kerning
			total_width += mFontFreetype->getXKerning(wchars[i-1], wch);
		}

		// Round after kerning.
		total_width = (F32)ll_round(total_width);
	}

	if (drawable_chars == 0)
	{
		return start_pos; // just draw last character
	}
	else
	{
		// if only 1 character is drawable, we want to return start_pos as the first character to draw
		// if 2 are drawable, return start_pos and character before start_pos, etc.
		return start_pos + 1 - drawable_chars;
	}

}

S32 LLFontGL::charFromPixelOffset(const llwchar* wchars, S32 begin_offset, F32 target_x, F32 max_pixels, S32 max_chars, BOOL round) const
{
	if (!wchars || !wchars[0] || max_chars == 0)
	{
		return 0;
	}

	F32 cur_x = 0;

	target_x *= sScaleX;

	// max_chars is S32_MAX by default, so make sure we don't get overflow
	const S32 max_index = begin_offset + llmin(S32_MAX - begin_offset, max_chars - 1);

	F32 scaled_max_pixels =	max_pixels * sScaleX;

	const LLFontGlyphInfo* next_glyph = NULL;

	S32 pos;
	for (pos = begin_offset; pos < max_index; pos++)
	{
		llwchar wch = wchars[pos];
		if (!wch)
		{
			break; // done
		}

		const LLFontGlyphInfo* glyph = next_glyph;
		next_glyph = NULL;
		if(!glyph)
		{
			glyph = mFontFreetype->getGlyphInfo(wch);
		}

		F32 char_width = mFontFreetype->getXAdvance(glyph);

		if (round)
		{
			// Note: if the mouse is on the left half of the character, the pick is to the character's left
			// If it's on the right half, the pick is to the right.
			if (target_x  < cur_x + char_width*0.5f)
			{
				break;
			}
		}
		else if (target_x  < cur_x + char_width)
		{
			break;
		}

		if (scaled_max_pixels < cur_x + char_width)
		{
			break;
		}

		cur_x += char_width;

		if (((pos + 1) < max_index)
			&& (wchars[(pos + 1)]))
		{
			// Kern this puppy.
			next_glyph = mFontFreetype->getGlyphInfo(wchars[pos + 1]);
			cur_x += mFontFreetype->getXKerning(glyph, next_glyph);
		}

		// Round after kerning.
		cur_x = (F32)ll_round(cur_x);
	}

	return llmin(max_chars, pos - begin_offset);
}

const LLFontDescriptor& LLFontGL::getFontDesc() const
{
	return mFontDescriptor;
}

// static
void LLFontGL::initClass(F32 screen_dpi, F32 x_scale, F32 y_scale, const std::string& app_dir, const std::string& fonts_file, F32 size_mod, bool create_gl_textures)
{
	sVertDPI = (F32)llfloor(screen_dpi * y_scale);
	sHorizDPI = (F32)llfloor(screen_dpi * x_scale);
	sScaleX = x_scale;
	sScaleY = y_scale;
	sAppDir = app_dir;

	// Font registry init
	if (!sFontRegistry)
	{
		sFontRegistry = new LLFontRegistry(create_gl_textures, size_mod);

		// <FS:Kadah> User selectable fonts
		// load from install_dir/fonts
		const std::string xml_pathfont(gDirUtilp->getExpandedFilename(LL_PATH_FONTS, "", fonts_file));
		if (!sFontRegistry->parseFontInfo(xml_pathfont))
		{
			// attempt to load from user_settings/fonts
			const std::string xml_pathusr(gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS , "fonts", fonts_file));
			if (!sFontRegistry->parseFontInfo(xml_pathusr))
			{
				// fall back to default if specifed font settings file is not found -KC
				const string_vec_t xml_paths = gDirUtilp->findSkinnedFilenames(LLDir::XUI, "fonts.xml");

				if (xml_paths.empty())
				{
					// We didn't even find one single XUI file
					LL_ERRS() << "No fonts.xml found: " << LL_ENDL;
				}

				for (string_vec_t::const_iterator path_it = xml_paths.begin();
						path_it != xml_paths.end();
						++path_it)
				{
					if (!sFontRegistry->parseFontInfo(*path_it))
					{
						LL_WARNS() << "Bad font info file: " << *path_it << LL_ENDL;
					}
				}
			}
		}
		// </FS:Kadah>
	}
	else
	{
		sFontRegistry->reset();
	}
}

// Force standard fonts to get generated up front.
// This is primarily for error detection purposes.
// Don't do this during initClass because it can be slow and we want to get
// the viewer window on screen first. JC
// static
bool LLFontGL::loadDefaultFonts()
{
	bool succ = true;
	succ &= (NULL != getFontSansSerifSmall());
	succ &= (NULL != getFontSansSerif());
	succ &= (NULL != getFontSansSerifBig());
	succ &= (NULL != getFontSansSerifHuge());
	succ &= (NULL != getFontSansSerifBold());
	succ &= (NULL != getFontMonospace());
	succ &= (NULL != getFontExtChar());
	// <FS:CR> Advanced script editor
	succ &= (NULL != getFontScripting());
	succ &= (NULL != getFontOCRA());
	// </FS:CR>
	return succ;
}

// static
void LLFontGL::destroyDefaultFonts()
{
	// Remove the actual fonts.
	delete sFontRegistry;
	sFontRegistry = NULL;
}

//static
void LLFontGL::destroyAllGL()
{
	if (sFontRegistry)
	{
		sFontRegistry->destroyGL();
	}
}

// static
U8 LLFontGL::getStyleFromString(const std::string &style)
{
	S32 ret = 0;
	if (style.find("BOLD") != style.npos)
	{
		ret |= BOLD;
	}
	if (style.find("ITALIC") != style.npos)
	{
		ret |= ITALIC;
	}
	if (style.find("UNDERLINE") != style.npos)
	{
		ret |= UNDERLINE;
	}
	return ret;
}

// static
std::string LLFontGL::getStringFromStyle(U8 style)
{
	std::string style_string;
	if (style == NORMAL)
	{
		style_string += "|NORMAL";
	}
	if (style & BOLD)
	{
		style_string += "|BOLD";
	}
	if (style & ITALIC)
	{
		style_string += "|ITALIC";
	}
	if (style & UNDERLINE)
	{
		style_string += "|UNDERLINE";
	}
	return style_string;
}

// static
std::string LLFontGL::nameFromFont(const LLFontGL* fontp)
{
	return fontp->mFontDescriptor.getName();
}

// static
std::string LLFontGL::sizeFromFont(const LLFontGL* fontp)
{
	return fontp->mFontDescriptor.getSize();
}

// static
std::string LLFontGL::nameFromHAlign(LLFontGL::HAlign align)
{
	if (align == LEFT)			return std::string("left");
	else if (align == RIGHT)	return std::string("right");
	else if (align == HCENTER)	return std::string("center");
	else return std::string();
}

// static
LLFontGL::HAlign LLFontGL::hAlignFromName(const std::string& name)
{
	LLFontGL::HAlign gl_hfont_align = LLFontGL::LEFT;
	if (name == "left")
	{
		gl_hfont_align = LLFontGL::LEFT;
	}
	else if (name == "right")
	{
		gl_hfont_align = LLFontGL::RIGHT;
	}
	else if (name == "center")
	{
		gl_hfont_align = LLFontGL::HCENTER;
	}
	//else leave left
	return gl_hfont_align;
}

// static
std::string LLFontGL::nameFromVAlign(LLFontGL::VAlign align)
{
	if (align == TOP)			return std::string("top");
	else if (align == VCENTER)	return std::string("center");
	else if (align == BASELINE)	return std::string("baseline");
	else if (align == BOTTOM)	return std::string("bottom");
	else return std::string();
}

// static
LLFontGL::VAlign LLFontGL::vAlignFromName(const std::string& name)
{
	LLFontGL::VAlign gl_vfont_align = LLFontGL::BASELINE;
	if (name == "top")
	{
		gl_vfont_align = LLFontGL::TOP;
	}
	else if (name == "center")
	{
		gl_vfont_align = LLFontGL::VCENTER;
	}
	else if (name == "baseline")
	{
		gl_vfont_align = LLFontGL::BASELINE;
	}
	else if (name == "bottom")
	{
		gl_vfont_align = LLFontGL::BOTTOM;
	}
	//else leave baseline
	return gl_vfont_align;
}

//static
LLFontGL* LLFontGL::getFontMonospace()
{
	static LLFontGL* fontp = getFont(LLFontDescriptor("Monospace","Monospace",0));
	return fontp;
}

//static
LLFontGL* LLFontGL::getFontSansSerifSmall()
{
	static LLFontGL* fontp = getFont(LLFontDescriptor("SansSerif","Small",0));
	return fontp;
}

//static
LLFontGL* LLFontGL::getFontSansSerif()
{
	static LLFontGL* fontp = getFont(LLFontDescriptor("SansSerif","Medium",0));
	return fontp;
}

//static
LLFontGL* LLFontGL::getFontSansSerifBig()
{
	static LLFontGL* fontp = getFont(LLFontDescriptor("SansSerif","Large",0));
	return fontp;
}

//static
LLFontGL* LLFontGL::getFontSansSerifHuge()
{
	static LLFontGL* fontp = getFont(LLFontDescriptor("SansSerif","Huge",0));
	return fontp;
}

//static
LLFontGL* LLFontGL::getFontSansSerifBold()
{
	static LLFontGL* fontp = getFont(LLFontDescriptor("SansSerif","Medium",BOLD));
	return fontp;
}

// <FS:CR> Advanced Script Editor
//static
LLFontGL* LLFontGL::getFontScripting()
{
	static LLFontGL* fontp = getFont(LLFontDescriptor("Scripting","Scripting",0));
	return fontp;
}

//static
LLFontGL* LLFontGL::getFontOCRA()
{
	static LLFontGL* fontp = getFont(LLFontDescriptor("OCRA","Monospace",0));
	return fontp;
}
// </FS:CR>

//static
LLFontGL* LLFontGL::getFontExtChar()
{
	return getFontSansSerif();
}

//static
LLFontGL* LLFontGL::getFont(const LLFontDescriptor& desc)
{
	return sFontRegistry->getFont(desc);
}

//static
LLFontGL* LLFontGL::getFontByName(const std::string& name)
{
	// check for most common fonts first
	if (name == "SANSSERIF")
	{
		return getFontSansSerif();
	}
	else if (name == "SANSSERIF_SMALL")
	{
		return getFontSansSerifSmall();
	}
	else if (name == "SANSSERIF_BIG")
	{
		return getFontSansSerifBig();
	}
	// <FS:CR> Advanced script editor
	//else if (name == "SMALL" || name == "OCRA")
	else if (name == "SMALL")
	// </FS:CR>
	{
		// *BUG: Should this be "MONOSPACE"?
		// Does "SMALL" mean "SERIF"?
		return getFontMonospace();
	}
	// <FS:CR> Advanced script editor
	else if (name == "OCRA")
	{
		return getFontOCRA();
	}
	else if (name == "Scripting")
	{
		return getFontScripting();
	}
	else if (name == "Monospace")
	{
		return getFontMonospace();
	}
	// </FS:CR>
	else
	{
		return NULL;
	}
}

//static
LLFontGL* LLFontGL::getFontDefault()
{
	return getFontSansSerif(); // Fallback to sans serif as default font
}

// static
std::string LLFontGL::getFontPathSystem()
{
#if LL_DARWIN
    // HACK for Mac OS X
    return "/System/Library/Fonts/";

#elif LL_WINDOWS
    auto system_root = LLStringUtil::getenv("SystemRoot");
    if (! system_root.empty())
    {
        std::string fontpath(gDirUtilp->add(system_root, "fonts") + gDirUtilp->getDirDelimiter());
        LL_INFOS() << "from SystemRoot: " << fontpath << LL_ENDL;
        return fontpath;
    }

    wchar_t *pwstr = NULL;
    HRESULT okay = SHGetKnownFolderPath(FOLDERID_Fonts, 0, NULL, &pwstr);
    if (SUCCEEDED(okay) && pwstr)
    {
        std::string fontpath(ll_convert_wide_to_string(pwstr));
        // SHGetKnownFolderPath() contract requires us to free pwstr
        CoTaskMemFree(pwstr);
        LL_INFOS() << "from SHGetKnownFolderPath(): " << fontpath << LL_ENDL;
        return fontpath;
    }
#endif

    LL_WARNS() << "Could not determine system fonts path" << LL_ENDL;
    return {};
}

// static
std::string LLFontGL::getFontPathLocal()
{
	std::string local_path;

	// Backup files if we can't load from system fonts directory.
	// We could store this in an end-user writable directory to allow
	// end users to switch fonts.
	if (LLFontGL::sAppDir.length())
	{
		// use specified application dir to look for fonts
		local_path = LLFontGL::sAppDir + "/fonts/";
	}
	else
	{
		// assume working directory is executable directory
		local_path = "./fonts/";
	}
	return local_path;
}

LLFontGL::LLFontGL(const LLFontGL &source)
{
	LL_ERRS() << "Not implemented!" << LL_ENDL;
}

LLFontGL &LLFontGL::operator=(const LLFontGL &source)
{
	LL_ERRS() << "Not implemented" << LL_ENDL;
	return *this;
}

// <FS:Ansariel> Remove QUADS rendering mode
//void LLFontGL::renderQuad(LLVector3* vertex_out, LLVector2* uv_out, LLColor4U* colors_out, const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4U& color, F32 slant_amt) const
//{
//	S32 index = 0;
//
//	vertex_out[index] = LLVector3(screen_rect.mRight, screen_rect.mTop, 0.f);
//	uv_out[index] = LLVector2(uv_rect.mRight, uv_rect.mTop);
//	colors_out[index] = color;
//	index++;
//
//	vertex_out[index] = LLVector3(screen_rect.mLeft, screen_rect.mTop, 0.f);
//	uv_out[index] = LLVector2(uv_rect.mLeft, uv_rect.mTop);
//	colors_out[index] = color;
//	index++;
//
//	vertex_out[index] = LLVector3(screen_rect.mLeft, screen_rect.mBottom, 0.f);
//	uv_out[index] = LLVector2(uv_rect.mLeft, uv_rect.mBottom);
//	colors_out[index] = color;
//	index++;
//
//	vertex_out[index] = LLVector3(screen_rect.mRight, screen_rect.mBottom, 0.f);
//	uv_out[index] = LLVector2(uv_rect.mRight, uv_rect.mBottom);
//	colors_out[index] = color;
//}
void LLFontGL::renderTriangle(LLVector3* vertex_out, LLVector2* uv_out, LLColor4U* colors_out, const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4U& color, F32 slant_amt) const
{
	S32 index = 0;

	vertex_out[index] = LLVector3(screen_rect.mRight, screen_rect.mTop, 0.f);
	uv_out[index] = LLVector2(uv_rect.mRight, uv_rect.mTop);
	colors_out[index] = color;
	index++;

	vertex_out[index] = LLVector3(screen_rect.mLeft, screen_rect.mTop, 0.f);
	uv_out[index] = LLVector2(uv_rect.mLeft, uv_rect.mTop);
	colors_out[index] = color;
	index++;

	vertex_out[index] = LLVector3(screen_rect.mLeft, screen_rect.mBottom, 0.f);
	uv_out[index] = LLVector2(uv_rect.mLeft, uv_rect.mBottom);
	colors_out[index] = color;
	index++;

	vertex_out[index] = LLVector3(screen_rect.mRight, screen_rect.mTop, 0.f);
	uv_out[index] = LLVector2(uv_rect.mRight, uv_rect.mTop);
	colors_out[index] = color;
	index++;

	vertex_out[index] = LLVector3(screen_rect.mLeft, screen_rect.mBottom, 0.f);
	uv_out[index] = LLVector2(uv_rect.mLeft, uv_rect.mBottom);
	colors_out[index] = color;
	index++;

	vertex_out[index] = LLVector3(screen_rect.mRight, screen_rect.mBottom, 0.f);
	uv_out[index] = LLVector2(uv_rect.mRight, uv_rect.mBottom);
	colors_out[index] = color;
}
// </FS:Ansariel>

void LLFontGL::drawGlyph(S32& glyph_count, LLVector3* vertex_out, LLVector2* uv_out, LLColor4U* colors_out, const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4U& color, U8 style, ShadowType shadow, F32 drop_shadow_strength) const
{
	F32 slant_offset;
	slant_offset = ((style & ITALIC) ? ( -mFontFreetype->getAscenderHeight() * 0.2f) : 0.f);

	//FIXME: bold and drop shadow are mutually exclusive only for convenience
	//Allow both when we need them.
	if (style & BOLD)
	{
		for (S32 pass = 0; pass < 2; pass++)
		{
			LLRectf screen_rect_offset = screen_rect;

			screen_rect_offset.translate((F32)(pass * BOLD_OFFSET), 0.f);
			// <FS:Ansariel> Remove QUADS rendering mode
			//renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect_offset, uv_rect, color, slant_offset);
			renderTriangle(&vertex_out[glyph_count * 6], &uv_out[glyph_count * 6], &colors_out[glyph_count * 6], screen_rect_offset, uv_rect, color, slant_offset);
			// </FS:Ansariel>
			glyph_count++;
		}
	}
	else if (shadow == DROP_SHADOW_SOFT)
	{
		LLColor4U shadow_color = LLFontGL::sShadowColor;
		shadow_color.mV[VALPHA] = U8(color.mV[VALPHA] * drop_shadow_strength * DROP_SHADOW_SOFT_STRENGTH);
		for (S32 pass = 0; pass < 5; pass++)
		{
			LLRectf screen_rect_offset = screen_rect;

			switch(pass)
			{
			case 0:
				screen_rect_offset.translate(-1.f, -1.f);
				break;
			case 1:
				screen_rect_offset.translate(1.f, -1.f);
				break;
			case 2:
				screen_rect_offset.translate(1.f, 1.f);
				break;
			case 3:
				screen_rect_offset.translate(-1.f, 1.f);
				break;
			case 4:
				screen_rect_offset.translate(0, -2.f);
				break;
			}

			// <FS:Ansariel> Remove QUADS rendering mode
			//renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect_offset, uv_rect, shadow_color, slant_offset);
			renderTriangle(&vertex_out[glyph_count * 6], &uv_out[glyph_count * 6], &colors_out[glyph_count * 6], screen_rect_offset, uv_rect, shadow_color, slant_offset);
			// </FS:Ansariel>
			glyph_count++;
		}
		// <FS:Ansariel> Remove QUADS rendering mode
		//renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect, uv_rect, color, slant_offset);
		renderTriangle(&vertex_out[glyph_count * 6], &uv_out[glyph_count * 6], &colors_out[glyph_count * 6], screen_rect, uv_rect, color, slant_offset);
		// </FS:Ansariel>
		glyph_count++;
	}
	else if (shadow == DROP_SHADOW)
	{
		LLColor4U shadow_color = LLFontGL::sShadowColor;
		shadow_color.mV[VALPHA] = U8(color.mV[VALPHA] * drop_shadow_strength);
		LLRectf screen_rect_shadow = screen_rect;
		screen_rect_shadow.translate(1.f, -1.f);
		// <FS:Ansariel> Remove QUADS rendering mode
		//renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect_shadow, uv_rect, shadow_color, slant_offset);
		//glyph_count++;
		//renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect, uv_rect, color, slant_offset);
		renderTriangle(&vertex_out[glyph_count * 6], &uv_out[glyph_count * 6], &colors_out[glyph_count * 6], screen_rect_shadow, uv_rect, shadow_color, slant_offset);
		glyph_count++;
		renderTriangle(&vertex_out[glyph_count * 6], &uv_out[glyph_count * 6], &colors_out[glyph_count * 6], screen_rect, uv_rect, color, slant_offset);
		// </FS:Ansariel>
		glyph_count++;
	}
	else // normal rendering
	{
		// <FS:Ansariel> Remove QUADS rendering mode
		//renderQuad(&vertex_out[glyph_count * 4], &uv_out[glyph_count * 4], &colors_out[glyph_count * 4], screen_rect, uv_rect, color, slant_offset);
		renderTriangle(&vertex_out[glyph_count * 6], &uv_out[glyph_count * 6], &colors_out[glyph_count * 6], screen_rect, uv_rect, color, slant_offset);
		// </FS:Ansariel>
		glyph_count++;
	}
}

max_stars_repo_name: SaladDais/LLUDP-Encryption

max_issues_repo_name: SaladDais/LLUDP-Encryption

max_forks_repo_name: SaladDais/LLUDP-Encryption


text:
// Copyright (c) 2015-2017
// Author: Chrono Law
#ifndef _NGX_VAR_HPP
#define _NGX_VAR_HPP

//#include <boost/format.hpp>
//#include <boost/utility/string_ref.hpp>

#include "NgxString.hpp"
#include "NgxException.hpp"

class NgxVariableValue final : public NgxWrapper<ngx_variable_value_t>
{
public:
    typedef NgxWrapper<ngx_variable_value_t> super_type;
    typedef NgxVariableValue this_type;
public:
    NgxVariableValue(ngx_variable_value_t* v):
        super_type(v)
    {}

    NgxVariableValue(ngx_variable_value_t& v):
        super_type(v)
    {}

    ~NgxVariableValue() = default;
public:
    void set(ngx_str_t& str, bool clear = false)
    {
        set(&str, clear);
    }

    void set(ngx_str_t* str, bool clear = false)
    {
        get()->len = clear ? 0 : str->len;
        get()->data = clear ? nullptr : str->data;

        get()->valid = !clear;
        get()->not_found = clear;
        get()->no_cacheable = false;
    }
public:
    bool valid() const
    {
        return get() && get()->valid && !get()->not_found;
    }

    ngx_str_t str() const
    {
        return valid()?
               ngx_str_t{get()->len, get()->data}:
               ngx_str_t ngx_null_string;
    }
};

inline namespace ngx_variable_types {
#ifndef ngx_stream_cpp_version  //ngx_http_variable

#define NGX_VAR_CHANGEABLE  NGX_HTTP_VAR_CHANGEABLE
#define NGX_VAR_INDEXED     NGX_HTTP_VAR_INDEXED

using NgxCtxCoreModule      = NgxHttpCoreModule;

using ngx_variable_ctx_t    = ngx_http_request_t;
using ngx_variable_t        = ngx_http_variable_t;
using ngx_set_variable_pt   = ngx_http_set_variable_pt;
using ngx_get_variable_pt   = ngx_http_get_variable_pt;

static auto ngx_add_variable = &ngx_http_add_variable;
static auto ngx_get_variable = &ngx_http_get_variable;

#else   //ngx_stream_variable

using NgxCtxCoreModule      = NgxStreamCoreModule;

#define NGX_VAR_CHANGEABLE  NGX_STREAM_VAR_CHANGEABLE
#define NGX_VAR_INDEXED     NGX_STREAM_VAR_INDEXED

using ngx_variable_ctx_t    = ngx_stream_session_t;
using ngx_variable_t        = ngx_stream_variable_t;
using ngx_set_variable_pt   = ngx_stream_set_variable_pt;
using ngx_get_variable_pt   = ngx_stream_get_variable_pt;

static auto ngx_add_variable = &ngx_stream_add_variable;
static auto ngx_get_variable = &ngx_stream_get_variable;

#endif
}

class NgxVariable final
{
public:
    typedef NgxVariable         this_type;
    typedef boost::string_ref   string_ref_type;
public:
    NgxVariable(ngx_variable_ctx_t* r, string_ref_type name):
        m_r(r), m_pool(r)
    {
        m_name = m_pool.dup(name);
        m_key = ngx_hash_strlow(m_name.data, m_name.data, m_name.len);
    }

    ~NgxVariable() = default;
public:
    ngx_str_t get() const
    {
        NgxVariableValue vv = ngx_get_variable(m_r,
            const_cast<ngx_str_t*>(&m_name), m_key);

        return vv.str();
    }

    bool set(string_ref_type value) const
    {
        auto& cmcf = NgxCtxCoreModule::instance().conf().main(m_r);

        // p = void*
        auto p = ngx_hash_find(&cmcf.variables_hash,
                                m_key, m_name.data, m_name.len);

        // not found
        if(!p)
        {
            return false;
        }

        auto v = reinterpret_cast<ngx_variable_t*>(p);

        // not changeable
        if(!(v->flags & NGX_VAR_CHANGEABLE))
        {
            return false;
        }

        auto val = m_pool.dup(value);

        NgxVariableValue vv = v->set_handler ?
            m_pool.alloc<ngx_variable_value_t>():
            // no set handler but indexed in request
            ((v->flags & NGX_VAR_INDEXED)?
                &m_r->variables[v->index] : nullptr);

        if(!vv)
        {
            return false;
        }

        vv.set(val, value.empty());

        if(v->set_handler)
        {
            v->set_handler(m_r, vv, v->data);
        }

        return true;
    }
public:
    operator ngx_str_t() const
    {
        return get();
    }

    void operator=(string_ref_type value) const
    {
        set(value);
    }
public:
    template<typename T>
    friend T& operator<<(T& o, const this_type& x)
    {
        //o << x.get();     // non-deducible context error

        auto s = x.get();
        o.write(reinterpret_cast<const char*>(s.data), s.len);
        return o;
    }
private:
    ngx_variable_ctx_t* m_r = nullptr;
    NgxPool             m_pool;
    ngx_str_t           m_name = ngx_null_string;
    ngx_uint_t          m_key = 0;
};

class NgxVarManager final
{
public:
    typedef NgxVarManager          this_type;
    typedef boost::string_ref      string_ref_type;
public:
    NgxVarManager(ngx_variable_ctx_t* r): m_r(r)
    {}
    ~NgxVarManager() = default;
public:
    NgxVariable operator[](string_ref_type name) const
    {
        return NgxVariable(m_r, name);
    }
private:
    ngx_variable_ctx_t* m_r = nullptr;
};

template<ngx_variable_t*(*get_vars)() = nullptr>
class NgxVariables final
{
public:
    typedef NgxVariables    this_type;
    typedef ngx_variable_t  var_type;
public:
    static ngx_int_t init(ngx_conf_t *cf)
    {
        if(!get_vars)
        {
            return NGX_OK;
        }

        for (auto v = get_vars(); v->name.len; ++v)
        {
            auto var = ngx_add_variable(cf, &v->name, v->flags);

            NgxException::fail(!var);

            var->get_handler = v->get_handler;
            var->data = reinterpret_cast<uintptr_t>(v->data);
        }

        return NGX_OK;
    }
public:
    static var_type* create(ngx_conf_t *cf, ngx_str_t& name, ngx_uint_t flags = 0)
    {
        auto p = ngx_add_variable(cf, &name, flags);

        NgxException::require(p);

        return p;
    }
};

#endif  //_NGX_VAR_HPP

ext: hpp


text:
#ifndef CAST_HPP
#define CAST_HPP

#include <string>
#include <sstream>
#include <iomanip>
#include <type_traits>

#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/trim.hpp>

namespace osrm
{
namespace util
{

namespace cast
{
template <typename Enumeration>
inline auto enum_to_underlying(Enumeration const value) ->
    typename std::underlying_type<Enumeration>::type
{
    return static_cast<typename std::underlying_type<Enumeration>::type>(value);
}

template <typename T, int Precision = 6> inline std::string to_string_with_precision(const T x)
{
    static_assert(std::is_arithmetic<T>::value, "integral or floating point type required");

    std::ostringstream out;
    out << std::fixed << std::setprecision(Precision) << x;
    auto rv = out.str();

    // Javascript has no separation of float / int, digits without a '.' are integral typed
    // X.Y.0 -> X.Y
    // X.0 -> X
    boost::trim_right_if(rv, boost::is_any_of("0"));
    boost::trim_right_if(rv, boost::is_any_of("."));
    // Note:
    //  - assumes the locale to use '.' as digit separator
    //  - this is not identical to:  trim_right_if(rv, is_any_of('0 .'))

    return rv;
}
}
}
}

#endif // CAST_HPP

max_stars_repo_name: mortada/osrm-backend

max_issues_repo_name: mortada/osrm-backend

max_forks_repo_name: mortada/osrm-backend


text:
/*

Copyright (c) 2016, Project OSRM contributors
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

Redistributions of source code must retain the above copyright notice, this list
of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

*/

#ifndef CONTRACTOR_OPTIONS_HPP
#define CONTRACTOR_OPTIONS_HPP

#include "updater/updater_config.hpp"

#include <boost/filesystem/path.hpp>

#include <string>

namespace osrm
{
namespace contractor
{

struct ContractorConfig
{
    ContractorConfig() : requested_num_threads(0) {}

    // Infer the output names from the path of the .osrm file
    void UseDefaultOutputNames()
    {
        level_output_path = osrm_input_path.string() + ".level";
        core_output_path = osrm_input_path.string() + ".core";
        graph_output_path = osrm_input_path.string() + ".hsgr";
        node_file_path = osrm_input_path.string() + ".enw";
        updater_config.osrm_input_path = osrm_input_path;
        updater_config.UseDefaultOutputNames();
    }

    updater::UpdaterConfig updater_config;

    boost::filesystem::path osrm_input_path;

    std::string level_output_path;
    std::string core_output_path;
    std::string graph_output_path;

    std::string node_file_path;

    bool use_cached_priority;

    unsigned requested_num_threads;

    // A percentage of vertices that will be contracted for the hierarchy.
    // Offers a trade-off between preprocessing and query time.
    // The remaining vertices form the core of the hierarchy
    //(e.g. 0.8 contracts 80 percent of the hierarchy, leaving a core of 20%)
    double core_factor;
};
}
}

#endif // EXTRACTOR_OPTIONS_HPP

max_stars_repo_name: mbeckem/msc

max_issues_repo_name: mbeckem/msc

max_forks_repo_name: mbeckem/msc


text:
/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2018 Sylko Olzscher
 *
 */

#include <smf/http/srv/websocket.h>
#include <smf/http/srv/connections.h>
#include <cyng/json.h>
#include <cyng/vm/generator.h>
#include <cyng/vm/domain/log_domain.h>
#include <boost/assert.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <boost/functional/hash.hpp>

namespace node
{
	namespace http
	{
		websocket_session::websocket_session(cyng::logging::log_ptr logger
			, connections& cm
			, boost::asio::ip::tcp::socket&& socket
			, boost::uuids::uuid tag)
		: ws_(std::move(socket))
			, strand_(ws_.get_executor())
			, timer_(ws_.get_executor().context(), (std::chrono::steady_clock::time_point::max)())
			, buffer_()
			, logger_(logger)
			, connection_manager_(cm)
			, tag_(tag)
#if (BOOST_BEAST_VERSION < 167)
			, ping_cb_()
#endif
            , shutdown_(false)
		{}

		websocket_session::~websocket_session()
		{
// 			std::cerr << "websocket_session::~websocket_session()" << std::endl;
		}

		boost::uuids::uuid websocket_session::tag() const noexcept
		{
			return tag_;
		}

		void websocket_session::on_accept(boost::system::error_code ec)
		{
            // Happens when the timer closes the socket
			if (ec == boost::asio::error::operation_aborted)
			{
				CYNG_LOG_WARNING(logger_, tag() << " ws aborted - read");
				connection_manager_.stop_ws(tag());
				return;
			}

			if (ec)
			{
				CYNG_LOG_ERROR(logger_, tag() << " ws read error: " << ec << " - " << ec.message());
				connection_manager_.stop_ws(tag());
				return;
			}

			CYNG_LOG_TRACE(logger_, "ws accepted");

			// Read a message
			do_read();
		}

		// Called when the timer expires.
		void websocket_session::on_timer(boost::system::error_code ec, cyng::object obj)
		{
			BOOST_ASSERT(cyng::object_cast<websocket_session>(obj) == this);

            //
            //  no activities after shutdown
            //
            if (shutdown_)  return;

            if (ec && ec != boost::asio::error::operation_aborted)
			{
				CYNG_LOG_WARNING(logger_, tag() << " ws timer aborted - read");
				connection_manager_.stop_ws(tag());
				return;
			}

			// See if the timer really expired since the deadline may have moved.
			if (timer_.expiry() <= std::chrono::steady_clock::now())
			{
				// If this is the first time the timer expired,
				// send a ping to see if the other end is there.
				if (ws_.is_open() && ping_state_ == 0)
				{
					// Note that we are sending a ping
					ping_state_ = 1;

					// Set the timer
					timer_.expires_after(std::chrono::seconds(15));

					// Now send the ping
					ws_.async_ping({},
						boost::asio::bind_executor(
							strand_,
							std::bind(
								&websocket_session::on_ping,
								this,
								std::placeholders::_1)));
				}
				else
				{
					// The timer expired while trying to handshake,
					// or we sent a ping and it never completed or
					// we never got back a control frame, so close.
					//std::cerr << ec << std::endl;
                    CYNG_LOG_WARNING(logger_, "ws - incomplete ping");
					connection_manager_.stop_ws(tag());

                    // Closing the socket cancels all outstanding operations. They
					// will complete with boost::asio::error::operation_aborted
					//ws_.next_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
					//ws_.next_layer().close(ec);
					return;
				}
			}

			// Wait on the timer
			timer_.async_wait(boost::asio::bind_executor(strand_,
				std::bind(&websocket_session::on_timer
					, this
					, std::placeholders::_1
					, obj)));
		}

		// Called to indicate activity from the remote peer
		void websocket_session::activity()
		{
            //
            //  no activities after shutdown
            //
            if (shutdown_)  return;

            // Note that the connection is alive
			ping_state_ = 0;

			// Set the timer
			timer_.expires_after(std::chrono::seconds(15));
		}

		// Called after a ping is sent.
		void websocket_session::on_ping(boost::system::error_code ec)
		{
            //
            //  no activities after shutdown
            //
            if (shutdown_)  return;

            // Happens when the timer closes the socket
			if (ec == boost::asio::error::operation_aborted)
			{
				CYNG_LOG_WARNING(logger_, "ws aborted - ping");
				connection_manager_.stop_ws(tag());
				return;
			}

			if (ec)
			{
				CYNG_LOG_ERROR(logger_, "ping: " << ec << " - " << ec.message());
				connection_manager_.stop_ws(tag());
				return;
			}

			// Note that the ping was sent.
			if (ping_state_ == 1)
			{
				ping_state_ = 2;
			}
			else
			{
				// ping_state_ could have been set to 0
				// if an incoming control frame was received
				// at exactly the same time we sent a ping.
				BOOST_ASSERT(ping_state_ == 0);
			}
		}

		void websocket_session::on_control_callback(boost::beast::websocket::frame_type kind,
			boost::beast::string_view payload)
		{
            //
            //  no activities after shutdown
            //
            if (shutdown_)  return;

            boost::ignore_unused(kind, payload);

			switch (kind)
			{
				/// A close frame was received
			case boost::beast::websocket::frame_type::close:
 				CYNG_LOG_TRACE(logger_, "ws::close - " << tag_);
				break;

				/// A ping frame was received
			case boost::beast::websocket::frame_type::ping:
 				CYNG_LOG_TRACE(logger_, "ws::ping - " << tag_);
				break;

				/// A pong frame was received
			case boost::beast::websocket::frame_type::pong:
 				CYNG_LOG_TRACE(logger_, "ws::pong - " << tag_);
				break;

			default:
				break;
			}

			// Note that there is activity
			activity();
		}

		void websocket_session::do_read()
		{
            //
            //  no activities after shutdown
            //
            if (shutdown_)  return;

            // Read a message into our buffer
			ws_.async_read(	buffer_,
				boost::asio::bind_executor(strand_,
					std::bind(&websocket_session::on_read
						, this
						, std::placeholders::_1
						, std::placeholders::_2)));
		}

		void websocket_session::on_read(boost::system::error_code ec,
			std::size_t bytes_transferred)
		{
            //
            //  no activities after shutdown
            //
            if (shutdown_)  return;

			boost::ignore_unused(bytes_transferred);

			// Happens when the timer closes the socket
			if (ec == boost::asio::error::operation_aborted)
			{
				CYNG_LOG_WARNING(logger_, "ws aborted - read");
				do_close();
				connection_manager_.stop_ws(tag());
				return;
			}

			// This indicates that the websocket_session was closed
			if (ec == boost::beast::websocket::error::closed)
			{
				CYNG_LOG_WARNING(logger_, "ws closed - read");
				do_close();
				connection_manager_.stop_ws(tag());
				return;
			}

			if (ec)
			{
                CYNG_LOG_ERROR(logger_, "ws read "
                    << tag()
                    << ": "
                    << ec
                    << " - "
                    << ec.message());
                do_close();
				connection_manager_.stop_ws(tag());
				return;
			}

			// Note that there is activity
			activity();

			std::stringstream msg;
			msg << boost::beast::buffers(buffer_.data());
			const std::string str = msg.str();
			CYNG_LOG_TRACE(logger_, "ws " << tag() << " read - " << str);

			//
			//	execute on bus VM
			//
			//bus_->vm_.async_run(cyng::generate_invoke("ws.read", tag_, cyng::invoke("ws.push"), cyng::json::read(str)));
			connection_manager_.vm().async_run(cyng::generate_invoke("ws.read", tag(), cyng::json::read(str)));

			// Clear buffer
			ws_.text();
			ws_.text(ws_.got_text());

			buffer_.consume(buffer_.size());

			do_read();
		}

		void websocket_session::on_write(boost::system::error_code ec,
			std::size_t bytes_transferred)
		{
            //
            //  no activities after shutdown
            //
            if (shutdown_)  return;

            boost::ignore_unused(bytes_transferred);

			// Happens when the timer closes the socket
			if (ec == boost::asio::error::operation_aborted)
			{
				CYNG_LOG_WARNING(logger_, "ws aborted - write");
				do_close();
				connection_manager_.stop_ws(tag());
				return;
			}

			if (ec)
			{
				CYNG_LOG_ERROR(logger_, "ws write: " << ec << " - " << ec.message());
				do_close();
				connection_manager_.stop_ws(tag());
				return;
			}

			CYNG_LOG_TRACE(logger_, "ws write: " << bytes_transferred << " bytes");

			// Clear the buffer
			buffer_.consume(buffer_.size());

			// Do another read
			do_read();
		}

		void websocket_session::do_close()
		{
            //
            //  no activities after shutdown
            //
            if (shutdown_)  return;

            CYNG_LOG_TRACE(logger_, "ws::do_close(cancel timer)");
			timer_.cancel();

			//CYNG_LOG_TRACE(logger_, "ws::do_close(use count " << shared_from_this().use_count() << ")");

			// Send a TCP shutdown
			boost::system::error_code ec;
			ws_.next_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
			ws_.next_layer().close(ec);

			if (ec)
			{
				CYNG_LOG_WARNING(logger_, "ws::do_close(" << ec << ")");
			}

			// At this point the connection is closed gracefully
		}

        void websocket_session::do_shutdown()
        {
            shutdown_ = true;

            timer_.cancel();

            if (ws_.is_open())
            {
                CYNG_LOG_WARNING(logger_, "ws::do_shutdown(" << ws_.next_layer().remote_endpoint() << ")");
                // Send a TCP shutdown
                boost::system::error_code ec;
                ws_.next_layer().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
                ws_.next_layer().close(ec);
            }
            else
            {
                CYNG_LOG_WARNING(logger_, "ws::do_shutdown(" << tag_ << ")");
            }
        }

		bool websocket_session::send_msg(std::string const& msg)
		{
            //
            //  no activities after shutdown
            //
            if (shutdown_)  return false;

            if (ws_.is_open())
			{
			    CYNG_LOG_TRACE(logger_, "ws.send.json: " << msg);
				//ws_.lowest_layer().wait(boost::asio::ip::tcp::socket::wait_write);
			    ws_.write(boost::asio::buffer(msg));
				return true;
			}
		    CYNG_LOG_WARNING(logger_, "ws.send.json - closed " << msg);
			return false;
		}
	}
}

namespace cyng
{
	namespace traits
	{

#if defined(CYNG_LEGACY_MODE_ON)
		const char type_tag<node::http::websocket_session>::name[] = "plain-websocket";
#endif
	}	// traits
}

namespace std
{
	size_t hash<node::http::websocket_session>::operator()(node::http::websocket_session const& t) const noexcept
	{
		return boost::hash<boost::uuids::uuid>()(t.tag());
	}

	bool equal_to<node::http::websocket_session>::operator()(node::http::websocket_session const& t1, node::http::websocket_session const& t2) const noexcept
	{
		return t1.tag() == t2.tag();
	}

	bool less<node::http::websocket_session>::operator()(node::http::websocket_session const& t1, node::http::websocket_session const& t2) const noexcept
	{
		return t1.tag() < t2.tag();
	}

}

ext: cpp

max_stars_repo_name: solosTec/node

max_issues_repo_name: solosTec/node

max_forks_repo_name: solosTec/node


text:
#ifndef QUADRATURE_HPP
#define QUADRATURE_HPP

#include <Eigen/Dense>

namespace polyfem
{
	class Quadrature
	{
	public:
		Eigen::MatrixXd points;
		Eigen::VectorXd weights;
	};
}

#endif //QUADRATURE_HPP

max_stars_repo_name: ldXiao/polyfem

max_issues_repo_name: ldXiao/polyfem

max_forks_repo_name: ldXiao/polyfem


text:
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2016 The Super Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "validation.h"

#include "base/base.hpp"
#include "utils/arith_uint256.h"
#include "chaincontrol/chain.h"
#include "config/chainparams.h"
#include "chaincontrol/checkpoints.h"
#include "interface/ichaincomponent.h"
#include "sbtccore/checkqueue.h"
#include "config/consensus.h"
#include "merkle.h"
#include "chaincontrol/validation.h"
#include "sbtccore/cuckoocache.h"
#include "fs.h"
#include "hash.h"
#include "wallet/fees.h"
#include "sbtccore/transaction/policy.h"
#include "wallet/rbf.h"
#include "miner/pow.h"
#include "block.h"
#include "transaction/transaction.h"
#include "random.h"
#include "reverse_iterator.h"
#include "script/script.h"
#include "script/sigcache.h"
#include "script/standard.h"
#include "timedata.h"
#include "tinyformat.h"
#include "transaction/txdb.h"
#include "mempool/txmempool.h"
#include "framework/ui_interface.h"
#include "undo.h"
#include "utils/util.h"
#include "utils/utilmoneystr.h"
#include "utils/utilstrencodings.h"
#include "framework/validationinterface.h"
#include "framework/versionbits.h"
#include "framework/warnings.h"
#include "sbtcd/baseimpl.hpp"
#include "chaincontrol/blockfilemanager.h"

#include <atomic>
#include <sstream>

#include <boost/algorithm/string/replace.hpp>
#include <boost/algorithm/string/join.hpp>
#include <boost/thread.hpp>

#if defined(NDEBUG)
# error "Bitcoin cannot be compiled without assertions."
#endif

SET_CPP_SCOPED_LOG_CATEGORY(CID_BLOCK_CHAIN);

/**
 * Global state
 */

CCriticalSection cs_main;

CWaitableCriticalSection csBestBlock;
CConditionVariable cvBlockChange;
std::atomic_bool fImporting(false);
bool fTxIndex = false;
bool fHavePruned = false;
bool fPruneMode = false;
bool fIsBareMultisigStd = DEFAULT_PERMIT_BAREMULTISIG;
bool fRequireStandard = true;
bool fCheckpointsEnabled = DEFAULT_CHECKPOINTS_ENABLED;
uint64_t nPruneTarget = 0;
int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE;
bool fEnableReplacement = DEFAULT_ENABLE_REPLACEMENT;

ServiceFlags nLocalServices = NODE_NETWORK;
ServiceFlags nRelevantServices = NODE_NETWORK;

arith_uint256 nMinimumChainWork;

CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE);
CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE;

CBlockPolicyEstimator feeEstimator;

/** Constant stuff for coinbase transactions we create: */
CScript COINBASE_FLAGS;

const std::string strMessageMagic = "Bitcoin Signed Message:\n";
// Internal stuff

bool CheckFinalTx(const CTransaction &tx, int flags)
{
    AssertLockHeld(cs_main);
    GET_CHAIN_INTERFACE(ifChainObj);
    CChain &chainActive = ifChainObj->GetActiveChain();

    // By convention a negative value for flags indicates that the
    // current network-enforced consensus rules should be used. In
    // a future soft-fork scenario that would mean checking which
    // rules would be enforced for the next block and setting the
    // appropriate flags. At the present time no soft-forks are
    // scheduled, so no flags are set.
    flags = std::max(flags, 0);

    // CheckFinalTx() uses chainActive.Height()+1 to evaluate
    // nLockTime because when IsFinalTx() is called within
    // CBlock::AcceptBlock(), the height of the block *being*
    // evaluated is what is used. Thus if we want to know if a
    // transaction can be part of the *next* block, we need to call
    // IsFinalTx() with one more than chainActive.Height().
    const int nBlockHeight = chainActive.Height() + 1;

    // BIP113 will require that time-locked transactions have nLockTime set to
    // less than the median time of the previous block they're contained in.
    // When the next block is created its previous block will be the current
    // chain tip, so we use that to calculate the median time passed to
    // IsFinalTx() if LOCKTIME_MEDIAN_TIME_PAST is set.
    const int64_t nBlockTime = (flags & LOCKTIME_MEDIAN_TIME_PAST)
                               ? chainActive.Tip()->GetMedianTimePast()
                               : GetAdjustedTime();

    //    GET_VERIFY_INTERFACE(ifVerifyObj);
    return tx.IsFinalTx(nBlockHeight, nBlockTime);
}

bool TestLockPointValidity(const LockPoints *lp)
{
    AssertLockHeld(cs_main);
    assert(lp);

    GET_CHAIN_INTERFACE(ifChainObj);
    CChain &chainActive = ifChainObj->GetActiveChain();

    // If there are relative lock times then the maxInputBlock will be set
    // If there are no relative lock times, the LockPoints don't depend on the chain
    if (lp->maxInputBlock)
    {
        // Check whether chainActive is an extension of the block at which the LockPoints
        // calculation was valid.  If not LockPoints are no longer valid
        if (!chainActive.Contains(lp->maxInputBlock))
        {
            return false;
        }
    }

    // LockPoints still valid
    return true;
}

/** Return transaction in txOut, and if it was found inside a block, its hash is placed in hashBlock */
bool GetTransaction(const uint256 &hash, CTransactionRef &txOut, const Consensus::Params &consensusParams,
                    uint256 &hashBlock, bool fAllowSlow)
{
    CBlockIndex *pindexSlow = nullptr;

    LOCK(cs_main);
    GET_CHAIN_INTERFACE(ifChainObj);
    CChain &chainActive = ifChainObj->GetActiveChain();
    GET_TXMEMPOOL_INTERFACE(ifTxMempoolObj);
    CTxMemPool &mempool = ifTxMempoolObj->GetMemPool();

    CTransactionRef ptx = mempool.get(hash);
    if (ptx)
    {
        txOut = ptx;
        return true;
    }

    if (ifChainObj->IsTxIndex())
    {
        CDiskTxPos postx;
        if (ifChainObj->GetBlockTreeDB()->ReadTxIndex(hash, postx))
        {
            CAutoFile file(OpenBlockFile(postx, true), SER_DISK, CLIENT_VERSION);
            if (file.IsNull())
            {
                return rLogError("%s: OpenBlockFile failed", __func__);
            }
            CBlockHeader header;
            try
            {
                file >> header;
                fseek(file.Get(), postx.nTxOffset, SEEK_CUR);
                file >> txOut;
            } catch (const std::exception &e)
            {
                return rLogError("%s: Deserialize or I/O error - %s", __func__, e.what());
            }
            hashBlock = header.GetHash();
            if (txOut->GetHash() != hash)
            {
                return rLogError("%s: txid mismatch", __func__);
            }
            return true;
        }
    }

    if (fAllowSlow)
    { // use coin database to locate block that contains transaction, and scan it
        GET_CHAIN_INTERFACE(ifChainObj);
        CCoinsViewCache *pcoinsTip = ifChainObj->GetCoinsTip();
        const Coin &coin = AccessByTxid(*pcoinsTip, hash);
        if (!coin.IsSpent())
            pindexSlow = chainActive[coin.nHeight];
    }

    if (pindexSlow)
    {
        CBlock block;
        if (ReadBlockFromDisk(block, pindexSlow, consensusParams))
        {
            for (const auto &tx : block.vtx)
            {
                if (tx->GetHash() == hash)
                {
                    txOut = tx;
                    hashBlock = pindexSlow->GetBlockHash();
                    return true;
                }
            }
        }
    }

    return false;
}

// Protected by cs_main
VersionBitsCache versionbitscache;

int32_t ComputeBlockVersion(const CBlockIndex *pindexPrev, const Consensus::Params &params)
{
    LOCK(cs_main);
    int32_t nVersion = VERSIONBITS_TOP_BITS;

    for (int i = 0; i < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; i++)
    {
        if ((i == Consensus::DEPLOYMENT_SBTC_CONTRACT) && (pindexPrev != nullptr) &&
            (pindexPrev->nHeight >= params.SBTCContractForkHeight))
        {
            nVersion |= VersionBitsMask(params, (Consensus::DeploymentPos)i);
            continue;
        }
        ThresholdState state = VersionBitsState(pindexPrev, params, (Consensus::DeploymentPos)i, versionbitscache);
        if (state == THRESHOLD_LOCKED_IN || state == THRESHOLD_STARTED)
        {
            nVersion |= VersionBitsMask(params, (Consensus::DeploymentPos)i);
        }
    }

    return nVersion;
}

bool IsWitnessEnabled(const CBlockIndex *pindexPrev, const Consensus::Params &params)
{
    LOCK(cs_main);
    return (VersionBitsState(pindexPrev, params, Consensus::DEPLOYMENT_SEGWIT, versionbitscache) == THRESHOLD_ACTIVE);
}

// Compute at which vout of the block's coinbase transaction the witness
// commitment occurs, or -1 if not found.
int GetWitnessCommitmentIndex(const CBlock &block)
{
    int commitpos = -1;
    if (!block.vtx.empty())
    {
        for (size_t o = 0; o < block.vtx[0]->vout.size(); o++)
        {
            if (block.vtx[0]->vout[o].scriptPubKey.size() >= 38 && block.vtx[0]->vout[o].scriptPubKey[0] == OP_RETURN &&
                block.vtx[0]->vout[o].scriptPubKey[1] == 0x24 && block.vtx[0]->vout[o].scriptPubKey[2] == 0xaa &&
                block.vtx[0]->vout[o].scriptPubKey[3] == 0x21 && block.vtx[0]->vout[o].scriptPubKey[4] == 0xa9 &&
                block.vtx[0]->vout[o].scriptPubKey[5] == 0xed)
            {
                commitpos = o;
            }
        }
    }
    return commitpos;
}

void
UpdateUncommittedBlockStructures(CBlock &block, const CBlockIndex *pindexPrev, const Consensus::Params &consensusParams)
{
    int commitpos = GetWitnessCommitmentIndex(block);
    static const std::vector<unsigned char> nonce(32, 0x00);
    if (commitpos != -1 && IsWitnessEnabled(pindexPrev, consensusParams) && !block.vtx[0]->HasWitness())
    {
        CMutableTransaction tx(*block.vtx[0]);
        tx.vin[0].scriptWitness.stack.resize(1);
        tx.vin[0].scriptWitness.stack[0] = nonce;
        block.vtx[0] = MakeTransactionRef(std::move(tx));
    }
}

max_stars_repo_name: superbitcoin/SuperBitcoin

max_issues_repo_name: superbitcoin/SuperBitcoin

max_forks_repo_name: superbitcoin/SuperBitcoin


text:
//==================================================================================================
/*!
  @file

  @copyright 2016 NumScale SAS
  @copyright 2016 J.T. Lapreste

  Distributed under the Boost Software License, Version 1.0.
  (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
*/
//==================================================================================================
#ifndef BOOST_SIMD_FUNCTION_ONEPLUS_HPP_INCLUDED
#define BOOST_SIMD_FUNCTION_ONEPLUS_HPP_INCLUDED

#if defined(DOXYGEN_ONLY)
namespace boost { namespace simd
{

 /*!

    @ingroup group-arithmetic
    Function object implementing oneplus capabilities

    Returns the entry plus one, saturated in the entry type.
    If @c x is not @ref Nan, @c oneplus(x) is greater or equal to x.

    @par semantic:
    For any given value @c x of type @c T:

    @code
    T r = oneplus(x);
    @endcode

    The code is similar to:

    @code
    T r = (x == Valmax) ? x : inc(x)
    @endcode

    @see inc, plus, adds

    @par Alias

    incs

  **/
  const boost::dispatch::functor<tag::oneplus_> oneplus = {};
} }
#endif

#include <boost/simd/function/scalar/oneplus.hpp>
#include <boost/simd/function/simd/oneplus.hpp>

#endif


text:
//
// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//

#ifndef BOOST_BEAST_WEBSOCKET_STREAM_BASE_HPP
#define BOOST_BEAST_WEBSOCKET_STREAM_BASE_HPP

#include <boost/beast/websocket/option.hpp>
#include <boost/beast/websocket/detail/pmd_extension.hpp>
#include <boost/beast/zlib/deflate_stream.hpp>
#include <boost/beast/zlib/inflate_stream.hpp>
#include <boost/beast/core/buffers_suffix.hpp>
#include <boost/beast/core/error.hpp>
#include <boost/beast/core/detail/chacha.hpp>
#include <boost/beast/core/detail/integer_sequence.hpp>
#include <boost/align/aligned_alloc.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/core/exchange.hpp>
#include <atomic>
#include <cstdint>
#include <memory>
#include <new>
#include <random>

// Turn this on to avoid using thread_local
//#define BOOST_BEAST_NO_THREAD_LOCAL 1

#ifdef BOOST_BEAST_NO_THREAD_LOCAL
#include <atomic>
#include <mutex>
#endif

namespace boost {
namespace beast {
namespace websocket {
namespace detail {

// used to order reads and writes
class soft_mutex
{
    int id_ = 0;

public:
    soft_mutex() = default;
    soft_mutex(soft_mutex const&) = delete;
    soft_mutex& operator=(soft_mutex const&) = delete;

    soft_mutex(soft_mutex&& other) noexcept
        : id_(boost::exchange(other.id_, 0))
    {
    }

    soft_mutex& operator=(soft_mutex&& other) noexcept
    {
        id_ = other.id_;
        other.id_ = 0;
        return *this;
    }

    // VFALCO I'm not too happy that this function is needed
    void reset()
    {
        id_ = 0;
    }

    bool is_locked() const
    {
        return id_ != 0;
    }

    template<class T>
    bool is_locked(T const*) const
    {
        return id_ == T::id;
    }

    template<class T>
    void lock(T const*)
    {
        BOOST_ASSERT(id_ == 0);
        id_ = T::id;
    }

    template<class T>
    void unlock(T const*)
    {
        BOOST_ASSERT(id_ == T::id);
        id_ = 0;
    }

    template<class T>
    bool try_lock(T const*)
    {
        // If this assert goes off it means you are attempting to
        // simultaneously initiate more than one of same asynchronous
        // operation, which is not allowed. For example, you must wait
        // for an async_read to complete before performing another
        // async_read.
        //
        BOOST_ASSERT(id_ != T::id);
        if(id_ != 0)
            return false;
        id_ = T::id;
        return true;
    }

    template<class T>
    bool try_unlock(T const*)
    {
        if(id_ != T::id)
            return false;
        id_ = 0;
        return true;
    }
};

//------------------------------------------------------------------------------

struct stream_prng
{
    bool secure_prng_ = true;

    struct prng_type
    {
        std::minstd_rand fast;
        beast::detail::chacha<20> secure;

#if BOOST_BEAST_NO_THREAD_LOCAL
        prng_type* next = nullptr;
#endif

        prng_type(std::uint32_t const* v, std::uint64_t stream)
            : fast(static_cast<typename decltype(fast)::result_type>(
                v[0] + v[1] + v[2] + v[3] + v[4] + v[5] + v[6] + v[7] + stream))
            , secure(v, stream)
        {
        }
    };

    class prng_ref
    {
        prng_type* p_;

    public:
        prng_ref& operator=(prng_ref&&) = delete;

        explicit
        prng_ref(prng_type& p)
            : p_(&p)
        {
        }

        prng_ref(prng_ref&& other)
            : p_(boost::exchange(other.p_, nullptr))
        {
        }

#ifdef BOOST_BEAST_NO_THREAD_LOCAL
        ~prng_ref()
        {
            if(p_)
                pool::impl().release(*p_);
        }
#endif

        prng_type*
        operator->() const
        {
            return p_;
        }
    };

#ifndef BOOST_BEAST_NO_THREAD_LOCAL
    static
    prng_ref
    prng()
    {
        static std::atomic<std::uint64_t> stream{0};
        thread_local prng_type p{seed(), stream++};
        return prng_ref(p);
    }

#else
    static
    prng_ref
    prng()
    {
        return prng_ref(pool::impl().acquire());
    }

#endif

    static
    std::uint32_t const*
    seed(std::seed_seq* ss = nullptr)
    {
        static seed_data d(ss);
        return d.v;
    }

    std::uint32_t
    create_mask()
    {
        auto p = prng();
        if(secure_prng_)
            for(;;)
                if(auto key = p->secure())
                    return key;
        for(;;)
            if(auto key = p->fast())
                return key;
    }

private:
    struct seed_data
    {
        std::uint32_t v[8];

        explicit
        seed_data(std::seed_seq* pss)
        {
            if(! pss)
            {
                std::random_device g;
                std::seed_seq ss{
                    g(), g(), g(), g(), g(), g(), g(), g()};
                ss.generate(v, v+8);
            }
            else
            {
                pss->generate(v, v+8);
            }
        }
    };

#ifdef BOOST_BEAST_NO_THREAD_LOCAL
    class pool
    {
        prng_type* head_ = nullptr;
        std::atomic<std::uint64_t> n_{0};
        std::mutex m_;

    public:
        ~pool()
        {
            for(auto p = head_; p;)
            {
                auto next = p->next;
                p->~prng_type();
                boost::alignment::aligned_free(p);
                p = next;
            }
        }

        prng_type&
        acquire()
        {
            for(;;)
            {
                std::lock_guard<std::mutex> lock(m_);
                if(! head_)
                    break;
                auto p = head_;
                head_ = head_->next;
                return *p;
            }
            auto p = boost::alignment::aligned_alloc(
                16, sizeof(prng_type));
            if(! p)
                BOOST_THROW_EXCEPTION(std::bad_alloc{});
            return *(new(p) prng_type(seed(), n_++));
        }

        void
        release(prng_type& p)
        {
            std::lock_guard<std::mutex> lock(m_);
            p.next = head_;
            head_ = &p;
        }

        static
        pool&
        impl()
        {
            static pool instance;
            return instance;
        }
    };
#endif
};

//------------------------------------------------------------------------------

template<bool deflateSupported>
struct stream_base : stream_prng
{
    // State information for the permessage-deflate extension
    struct pmd_type
    {
        // `true` if current read message is compressed
        bool rd_set = false;

        zlib::deflate_stream zo;
        zlib::inflate_stream zi;
    };

    std::unique_ptr<pmd_type>   pmd_;           // pmd settings or nullptr
    permessage_deflate          pmd_opts_;      // local pmd options
    detail::pmd_offer           pmd_config_;    // offer (client) or negotiation (server)

    // return `true` if current message is deflated
    bool
    rd_deflated() const
    {
        return pmd_ && pmd_->rd_set;
    }

    // set whether current message is deflated
    // returns `false` on protocol violation
    bool
    rd_deflated(bool rsv1)
    {
        if(pmd_)
        {
            pmd_->rd_set = rsv1;
            return true;
        }
        return ! rsv1; // pmd not negotiated
    }

    template<class ConstBufferSequence>
    bool
    deflate(
        boost::asio::mutable_buffer& out,
        buffers_suffix<ConstBufferSequence>& cb,
        bool fin,
        std::size_t& total_in,
        error_code& ec);

    void
    do_context_takeover_write(role_type role);

    void
    inflate(
        zlib::z_params& zs,
        zlib::Flush flush,
        error_code& ec);

    void
    do_context_takeover_read(role_type role);
};

template<>
struct stream_base<false> : stream_prng
{
    // These stubs are for avoiding linking in the zlib
    // code when permessage-deflate is not enabled.

    bool
    rd_deflated() const
    {
        return false;
    }

    bool
    rd_deflated(bool rsv1)
    {
        return ! rsv1;
    }

    template<class ConstBufferSequence>
    bool
    deflate(
        boost::asio::mutable_buffer&,
        buffers_suffix<ConstBufferSequence>&,
        bool,
        std::size_t&,
        error_code&)
    {
        return false;
    }

    void
    do_context_takeover_write(role_type)
    {
    }

    void
    inflate(
        zlib::z_params&,
        zlib::Flush,
        error_code&)
    {
    }

    void
    do_context_takeover_read(role_type)
    {
    }
};

} // detail
} // websocket
} // beast
} // boost

#endif