Let's talk about text... (FF_TYPE_TEXT)

FFGL, OSC, GLSL. If you like abbreviations, this is the forum for you
Post Reply
User avatar
subpixel
Hasn't felt like this about software in a long time
Posts: 152
Joined: Thu Jun 05, 2014 09:32
Location: Sydney, AU

Let's talk about text... (FF_TYPE_TEXT)

Post by subpixel »

Class CFFGLPluginManager declares (in FFGLPluginSDK.h):

Code: Select all

	virtual FFResult SetTextParameter(unsigned int index, const char *value);
	virtual char* GetTextParameter(unsigned int index);
with rather demotivating base class implementations (in FFGLPlyginSDK.cpp)

Code: Select all

FFResult CFreeFrameGLPlugin::SetTextParameter(unsigned int index, const char *value)
{
  return FF_FAIL;
}

char* CFreeFrameGLPlugin::GetTextParameter(unsigned int index)
{
  return (char *)FF_FAIL;
}					
In my subclass, SxplLabelParams, I declare

Code: Select all

	float GetFloatParameter(unsigned int dwIndex) override;
	char* GetTextParameter(unsigned int dwIndex) override;
and define

Code: Select all

FFResult SpxlLabelParams::SetTextParameter(unsigned int dwIndex, const char *value)
{
	// Check range
	if (dwIndex < 0 || dwIndex >= m_paramsCount)
		return FF_FAIL;

	// Grab a pointer to the relevant local paramater info struct
	LocalParamInfo * p = &m_localParams[dwIndex];

	if (value != NULL && value[0] != 0)
	{
		// Nonempty value, so use value
		// Avoid reallocating if not changing
		if (p->text != NULL && strcmp(p->text, value))
		{
			delete p->text;
			p->text = _strdup(value);
		}
	}
	else if (p->defaultText != NULL && p->defaultText[0] != 0)
	{
		// Value is empty, default is nonempty, so use default
		// Avoid reallocating if not changing
		if (p->text != NULL && strcmp(p->text, p->defaultText))
		{
			delete p->text;
			p->text = _strdup(p->defaultText);
		}
	}
	else
	{
		// Value and default are both empty, so save an empty string
		// Avoid reallocating if not changing
		if (p->text != NULL && p->text[0] != 0)
		{
			delete p->text;
			p->text = _strdup("");
		}
	}

	return FF_SUCCESS;
}

char* SpxlLabelParams::GetTextParameter(unsigned int dwIndex)
{
	char * retValue = "";

	// Check range
	if (0 <= dwIndex && dwIndex < m_paramsCount)
	{
		retValue = _strdup(m_localParams[dwIndex].text);
	};

	return retValue;
}
..where the local parameter info struct, LocalParamInfo, looks like...

Code: Select all

class SpxlLabelParams : public CFreeFrameGLPlugin
{
public:
	typedef struct LocalParamInfoStruct
	{
		unsigned int index;
		char * displayName;
		int ffType;
		float defaultValue;
		float value;
		char * defaultText;
		char * text;
		char * uniformName;
		GLint uniformLocation;

		LocalParamInfoStruct() :
			index(0),
			displayName(NULL),
			ffType(-1),
			value(0.0f),
			defaultValue(0.0f),
			defaultText(NULL),
			text(NULL),
			uniformName(NULL),
			uniformLocation(-1)
		{
			// Empty constructor
		}
	} LocalParamInfo;

// Other class stuff follows
}
That is to say, "text" and "defaultText" members are just char * pointers.

The FFGLSDK-provided declarations don't say much about how the "char *" parameter and return value are to be treated. I had some issues with my plugin crashing, and I don't know if it was because an earlier iteration had

Code: Select all

		retValue = m_localParams[dwIndex].text;
(without making a copy) and Resolume doing something bad with that pointer later.

Any insight?

I noticed that Resolume both sets every parameter value and requests the string version of every value for every frame, which is why I have comparisons and deletes in my code when I'm storing the value coming in from Resolume. I haven't got around to figuring out how to test if I'm leaking memory.

I was also kinda hoping to be able to have my plugin update the value of the text parameter in Resolume, but it seems Resolume does not display (nor perhaps in any way use) the string I return.

-subpixel

User avatar
flyingrub
Met Resolume in a bar the other day
Posts: 11
Joined: Thu Feb 21, 2019 10:24
Location: Out of space

Re: Let's talk about text... (FF_TYPE_TEXT)

Post by flyingrub »

I'm currently building a framework around FFGL, to help new user to start with it, you can find how I deal with text parameter here : https://github.com/flyingrub/FFGL-plugi ... #L156-L176. I don't want to deal with C function and memory myself so I cheated and created a

Code: Select all

std::vector<char> text = { 0 };
that contains my text data.

Menno
Team Resolume
Posts: 137
Joined: Tue Mar 12, 2013 13:56

Re: Let's talk about text... (FF_TYPE_TEXT)

Post by Menno »

A ffgl plugin is not allowed to make changes to it's param's values (other than initial value) and the returned char pointers dont pass ownership over that string along with it.

If you're using c++ i suggest you use the std::string class. In the SetTextParameter function you just assign the char* to the std string and in the GetTextParameter function you return value.c_str(). You can then remove all these custom allocations and comparisons.

User avatar
flyingrub
Met Resolume in a bar the other day
Posts: 11
Joined: Thu Feb 21, 2019 10:24
Location: Out of space

Re: Let's talk about text... (FF_TYPE_TEXT)

Post by flyingrub »

I had some issue with std::string returning a const value and over engineered the solution around it :roll: here is a simple solution using std::string. https://github.com/flyingrub/FFGL-plugi ... 5692cbdb3d

Menno
Team Resolume
Posts: 137
Joined: Tue Mar 12, 2013 13:56

Re: Let's talk about text... (FF_TYPE_TEXT)

Post by Menno »

I dont think there's any host who's going to write directly into the returned char pointer because no buffer size is exposed and thus writing to it would be terribly unsafe. Therefore it's safe to tell the compiler that it's all good and use a const_cast< char* >

leadedge
Hasn't felt like this about software in a long time
Posts: 104
Joined: Fri Feb 14, 2014 13:58

Re: Let's talk about text... (FF_TYPE_TEXT)

Post by leadedge »

I haven't worked with Freeframe for quite some time and so have not used the Resolume variant of the SDK. But I did find that for 64 bit I had to check that the pointer for SetTextParameter was not bad or it crashed. It's easy to check, so it would be good to know that the bug is not there for the Resolume code if anybody using Windows was good enough to test it.

Code: Select all

	UINT_PTR ucb = 1;

	switch (index) {
		case FFPARAM_SharingName:
			// Bug in FFGL 1.6 ?
			// Bad read pointer when the text entry field is empty
			// IsBadReadPtr(), IsBadWritePtr(), IsBadCodePtr(), IsBadStringPtr() for Windows
			if(!IsBadReadPtr((const void *)value, ucb)) {
				strcpy_s(UserSenderName, 256, value);
				return FF_SUCCESS;
			}
			else {
				printf("bad read pointer\n");
				// UserSenderNameString = value; // Crash here for std::string as well
			}
			break;
		default:
			break;
	}

User avatar
subpixel
Hasn't felt like this about software in a long time
Posts: 152
Joined: Thu Jun 05, 2014 09:32
Location: Sydney, AU

Re: Let's talk about text... (FF_TYPE_TEXT)

Post by subpixel »

Returing someString.c_str() is something I'm going to have to think about for a while.

c_str() method defined in <xstring>

C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\include\xstring

Code: Select all

	_NODISCARD _Ret_z_ const _Elem * c_str() const noexcept
		{	// return pointer to null-terminated immutable array
		return (this->_Get_data()._Myptr());
		}
So the return value is a pointer... to data owned by a string object. If that is a local variable then that is going to leave scope. Seems a bit dodgy.

Meanwhile, docs for the IsBadReadPtr() function at

https://docs.microsoft.com/en-us/window ... badreadptr

include this notice:
Important This function is obsolete and should not be used. Despite its name, it does not guarantee that the pointer is valid or that the memory pointed to is safe to use. For more information, see Remarks on this page.
I am writing 64-bit plugins and haven't encountered the bad pointer scenario you speak of yet.

leadedge
Hasn't felt like this about software in a long time
Posts: 104
Joined: Fri Feb 14, 2014 13:58

Re: Let's talk about text... (FF_TYPE_TEXT)

Post by leadedge »

OK thanks a lot for verifying that you have not seen the bad read pointer problem. It must be a bug because it's quite repeatable. I think it could point to something in the Freeframe SDK where the host pointer does not exist. Microsoft say the function is deprecated but give no other solution. Meanwhile it solves it me.

I need to digest and think about your comments about std strings. Freeframe is based around character arrays, and even some are not null terminated. But I still believe there could be something lurking there, so when I have a Freeframe project to work on, I will change to the Resolume version and report back what I find.

Post Reply