Not able to return out of recursion - c++

I have the following piece of code. It aims at traversing the [attached screenshot] Tree structure in depth first manner.
As you can see, I am interested in the highlighted entry in green -> Has Class( DatasetType ) node of this tree structure. This Tree structure is subjected to additions of new nodes by customers. So, I have to traverse the Tree structure to find my node of interest. I have formulated the below code. But And I can see that it identifies that node of my interest.
However, it is not stopping there. It is proceeding onto the next sibling i.e., Has Class( EPMJob ). I want my processing to stop. I am pretty sure that my way of returning stuff is missing something. but not able to pin point.
Any inputs are most welcome.
tag_t findHasTypeDatasetNodeInAMTree( tag_t amTreeNode )
{
CharPointer nodeName;
Response stat = askRuleName( amTreeNode, &nodeName );
CharPointer nodeArgument;
stat = askRuleArg( amTreeNode, &nodeArgument );
if( tc_strcmp( nodeName.getString(), "Has Class" ) == 0 && tc_strcmp( nodeArgument.getString(), "DatasetType" ) == 0 )
{
return amTreeNode;
}
int numChildNodes = 0;
TagPointer childNodes;
stat = askChildren( amTreeNode, &numChildNodes, &childNodes );
if( numChildNodes == 0 )
{
return NULLTAG;
}
// The following is the piece that needs attention.
// Do not want to NULL check here though
for( int inx = 0; inx < numChildNodes; ++inx )
{
findHasTypeDatasetNodeInAMTree( childNodes[inx] );
}
return NULLTAG;
}

I'm not sure what this is doing:
for( int inx = 0; inx < numChildNodes; ++inx )
{
findHasTypeDatasetNodeInAMTree( childNodes[inx] );
}
But I'm pretty sure it doesn't stop when you find something so the result is ALWAYS NULLTAG. How about something like:
for( int inx = 0; inx < numChildNodes; ++inx )
{
auto result = findHasTypeDatasetNodeInAMTree( childNodes[inx] );
if( result != NULLTAG )
return result;
}

Related

reversed DOS game uncompression code: is that maybe a known compression method (RLE,...) or self-invented?

its a file uncompression routine from the 1990 DOS game Alpha Waves game loader (https://www.mobygames.com/game/continuum)
based on my https://github.com/LowLevelMahn/alpha_waves_loader reverse engineering project
first i've reversed the loader with IDA to a binary equal assemble-able asm code:
https://github.com/LowLevelMahn/alpha_waves_loader/blob/db422a5475a1939427b6379e688d23844535b7a9/ae.asm#L970
then i've translated the code to fake-assembler code (keeping the semantic but be able to use 32bit C/C++ code)
https://github.com/LowLevelMahn/alpha_waves_loader/blob/db422a5475a1939427b6379e688d23844535b7a9/read_some_file_sub_4/original_port.cpp#L9
the last step was a small unit test comparing the original fake-assembler code against a more and more cleanuped version of the algorithm
https://github.com/LowLevelMahn/alpha_waves_loader/blob/db422a5475a1939427b6379e688d23844535b7a9/read_some_file_sub_4/cleanup_port.cpp#L151
the reversed algorithm works with all compressed game data, got 100% coverage and a unit-test, the variable names are still a bit clumsy as i didn't understand the uncompresse algorithm fully
i've got a small (except the test data size) unit-test that got a nearly 100% coverage of the algorithm (execept the uncompress block case - that can be skipped here)
compiles standalone - out-of the box with a C++14 compiler VS2017+, gcc, clang tested
https://github.com/LowLevelMahn/alpha_waves_loader/blob/main/read_some_file_sub_4/example.cpp
online compile & debug-able at: https://onlinegdb.com/VjiONQjAu
can anyone tell me if that is some sort of standard (un)compression algorithm from the early times
or something completely self-invented by the game creator? (its dramatically reduced compared to the original asm but still not super-trivial)
the code seems to be recursive - flattened by using a stack while uncompression
void val_3_non_0( uint8_t*& uncompressed_, const tables_t& tables_, const uint8_t val_3_ )
{
struct stack_vals_t
{
uint8_t val_0{};
uint8_t val_1{};
};
std::stack<stack_vals_t> stack;
auto helper1 = [&stack, &tables_]( const uint8_t val_7_ ) {
stack.push( { val_7_, tables_.table2[val_7_] } );
return tables_.table1[val_7_];
};
auto helper2 = [&stack]( uint8_t* val_7_, uint8_t* val_4_ ) {
if( stack.empty() )
{
return true;
}
const stack_vals_t stack_val = stack.top();
stack.pop();
*val_7_ = stack_val.val_0;
*val_4_ = stack_val.val_1;
return false;
};
uint8_t val_7 = val_3_;
uint8_t val_4 = helper1( val_7 );
while( true )
{
const uint8_t val_5 = val_4;
const uint8_t val_6 = tables_.table3[val_5];
if( val_6 == 0 )
{
*uncompressed_++ = val_4;
if( helper2( &val_7, &val_4 ) )
{
return;
}
}
else if( val_7 > val_6 )
{
val_7 = val_6;
val_4 = helper1( val_7 );
}
else
{
val_4 = val_7;
val_7 = val_6;
assert( stack.size() >= 0 );
while( true )
{
val_7 = tables_.table4[val_7];
if( val_7 == 0 )
{
*uncompressed_++ = val_5;
if( helper2( &val_7, &val_4 ) )
{
return;
}
break;
}
else if( val_7 < val_4 )
{
val_4 = helper1( val_7 );
break;
}
// another run
}
}
}
}

Adding XPointer/XPath searches to ALL(?) C++ JSON libraries, is it doable?

Is it possible to extend all(?) existing C++ JSON libraries with XPath/XPointer or subset with just one C++ implementation? At least those with iterators for object and array values?
I have reviewed three C++ JSON libraries (reviewing nlohmann, Boost.JSON and RapidJSON) to see the internals and check their search functionality. Some have implemented Json pointer. Json pointer is basic, almost like working with json as a name-value list.
XML has XPath and XPointer searches and rules are standardized. With XPath and XPointer you can do more.
One reason to reviewing these libraries was to see if it is possible to extend any of them with better search functionality. Or might it be possible to extend all(?) C++ JSON libraries at once?
A longer text describing this can be found here, trying to be brief.
I tried to do one traverse method that selects json values with one specific property name and that method should work an all tested JSON libraries. If I got that to work it may be possible to add more search logic and get it to work on almost all C++ JSON.
I got this C++ templated function to work an all tested json libraries. It can walk the JSON tree and select json values on all tested libraries.
What is needed to is to implement specializations of is_object, is_array, compare_name, get_value, begin and end. That are just one liners so it's easy.
template<typename json_value>
bool is_object( const json_value* p )
{ static_assert(sizeof(json_value) == 0, "Only specializations of is_object is allowed"); }
template<typename json_value>
bool is_array( const json_value* p )
{ static_assert(sizeof(json_value) == 0, "Only specializations of is_array is allowed"); }
template<typename iterator>
bool compare_name( iterator it, std::string_view stringName )
{ static_assert(sizeof(it) == 0, "Only specializations of compare_name is allowed"); }
template<typename iterator, typename json_value>
const json_value* get_value( iterator it )
{ static_assert(sizeof(it) == 0, "Only specializations of get_value is allowed"); }
template<typename iterator, typename json_value>
iterator begin( const json_value& v ) { return std::begin( v ); }
template<typename iterator, typename json_value>
iterator end( const json_value& v ) { return std::end( v ); }
// ------------------------------------------------
// Selects all json values that match property name
template<typename json_value, typename object_iterator,typename array_iterator = object_iterator>
uint32_t select( const json_value& jsonValue, std::string_view stringQuery, std::vector<const json_value*>* pvectorValue = nullptr )
{ assert( is_object( &jsonValue ) || is_array( &jsonValue ) );
uint32_t uCount = 0;
if( is_object( &jsonValue ) == true ) // found object ?
{
for( auto it = begin<object_iterator,json_value>( jsonValue ); it != end<object_iterator,json_value>( jsonValue ); it++ )
{
if( is_object( get_value<object_iterator,json_value>( it ) ) == true )
{ // found object, scan it
auto value = get_value<object_iterator,json_value>( it );
uCount += select<json_value,object_iterator>( *value, stringQuery, pvectorValue );
}
else if( is_array( get_value<object_iterator,json_value>( it ) ) == true )
{ // found array, scan it
auto parray = get_value<object_iterator,json_value>( it );
uCount += select<json_value,object_iterator,array_iterator>( *parray, stringQuery, pvectorValue );
}
else if( compare_name<object_iterator>( it, stringQuery ) == true )
{ // property name matches, store value if pointer to vector
if( pvectorValue != nullptr ) pvectorValue->push_back( get_value<object_iterator,json_value>( it ) );
uCount++;
}
}
}
else if( is_array( &jsonValue ) == true ) // found array
{
for( auto it = begin<array_iterator,json_value>( jsonValue ); it != end<array_iterator,json_value>( jsonValue ); it++ )
{
if( is_object( get_value<array_iterator,json_value>( it ) ) == true )
{ // found object, scan it
auto value = get_value<array_iterator,json_value>( it );
uCount += select<json_value,object_iterator>( *value, stringQuery, pvectorValue );
}
else if( is_array( get_value<array_iterator,json_value>( it ) ) == true )
{ // found array, scan it
auto parray = get_value<array_iterator,json_value>( it );
uCount += select<json_value,object_iterator,array_iterator>( *parray, stringQuery, pvectorValue );
}
}
}
return uCount;
}
if this works and if I haven't forgot something, shouldn't it be possible to extend all libraries with just one implementation? The additional logic for XPath and XPointer is not dependent on the implementation of these C++ JSON libraries.
Am I missing something

OpenVR - IVRSystem::GetControllerState always returns empty structs

I've been following Kamran Bigdely-Shamloo's article on how to get positional information from the HTC Vive and it has worked well so far. My next step was to "listen" to button presses. I've read the documentation and it says here that all I need to do is query IVRSystem::GetControllerStateand it'll return a
"struct with the current state of the controller"
This struct however always contains variables that have the 0 value. The following function is called in a while (true) loop from the main function.
bool CMainApplication::HandleInput()
{
SDL_Event sdlEvent;
bool bRet = false;
while ( SDL_PollEvent( &sdlEvent ) != 0 )
{
if ( sdlEvent.type == SDL_QUIT )
{
bRet = true;
}
else if ( sdlEvent.type == SDL_KEYDOWN )
{
if ( sdlEvent.key.keysym.sym == SDLK_ESCAPE
|| sdlEvent.key.keysym.sym == SDLK_q )
{
bRet = true;
}
if( sdlEvent.key.keysym.sym == SDLK_c )
{
m_bShowCubes = !m_bShowCubes;
}
}
}
// Process SteamVR events
// Periodically returns an event of type 404 ("VREvent_SceneApplicationChanged = 404, // data is process - The App actually drawing the scene changed (usually to or from the compositor)"
vr::VREvent_t event;
vr::VREvent_Controller_t controllerEvent;
std::chrono::milliseconds ms4;
while( m_pHMD->PollNextEvent( &event, sizeof( event ) ) )
{
ms4 = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch()
);
ProcessVREvent( &event);
printPositionalData(&event, ms4);
}
vr::VRControllerState_t state;
// Check every device attached, usually it's four devices
// Second if statement is never reached
for (int i = 0; i < 1000; i++) {
if (m_pHMD->GetControllerState(i, &state, sizeof(state))) {
dprintf("%d", i);
if (state.ulButtonPressed != 0 || state.unPacketNum != 0 || state.ulButtonTouched != 0) {
dprintf("Some action?");
}
}
}
dprintf("\n");
// Process SteamVR action state
// UpdateActionState is called each frame to update the state of the actions themselves. The application
// controls which action sets are active with the provided array of VRActiveActionSet_t structs.
vr::VRActiveActionSet_t actionSet = { 0 };
actionSet.ulActionSet = m_actionsetDemo;
vr::VRInput()->UpdateActionState( &actionSet, sizeof(actionSet), 1 );
m_bShowCubes = !GetDigitalActionState( m_actionHideCubes );
vr::VRInputValueHandle_t ulHapticDevice;
if ( GetDigitalActionRisingEdge( m_actionTriggerHaptic, &ulHapticDevice ) )
{
if ( ulHapticDevice == m_rHand[Left].m_source )
{
vr::VRInput()->TriggerHapticVibrationAction( m_rHand[Left].m_actionHaptic, 0, 1, 4.f, 1.0f, vr::k_ulInvalidInputValueHandle );
}
if ( ulHapticDevice == m_rHand[Right].m_source )
{
vr::VRInput()->TriggerHapticVibrationAction( m_rHand[Right].m_actionHaptic, 0, 1, 4.f, 1.0f, vr::k_ulInvalidInputValueHandle );
}
}
vr::InputAnalogActionData_t analogData;
if ( vr::VRInput()->GetAnalogActionData( m_actionAnalongInput, &analogData, sizeof( analogData ), vr::k_ulInvalidInputValueHandle ) == vr::VRInputError_None && analogData.bActive )
{
m_vAnalogValue[0] = analogData.x;
m_vAnalogValue[1] = analogData.y;
}
m_rHand[Left].m_bShowController = true;
m_rHand[Right].m_bShowController = true;
vr::VRInputValueHandle_t ulHideDevice;
if ( GetDigitalActionState( m_actionHideThisController, &ulHideDevice ) )
{
if ( ulHideDevice == m_rHand[Left].m_source )
{
m_rHand[Left].m_bShowController = false;
}
if ( ulHideDevice == m_rHand[Right].m_source )
{
m_rHand[Right].m_bShowController = false;
}
}
for ( EHand eHand = Left; eHand <= Right; ((int&)eHand)++ )
{
vr::InputPoseActionData_t poseData;
if ( vr::VRInput()->GetPoseActionData( m_rHand[eHand].m_actionPose, vr::TrackingUniverseStanding, 0, &poseData, sizeof( poseData ), vr::k_ulInvalidInputValueHandle ) != vr::VRInputError_None
|| !poseData.bActive || !poseData.pose.bPoseIsValid )
{
m_rHand[eHand].m_bShowController = false;
}
else
{
m_rHand[eHand].m_rmat4Pose = ConvertSteamVRMatrixToMatrix4( poseData.pose.mDeviceToAbsoluteTracking );
vr::InputOriginInfo_t originInfo;
if ( vr::VRInput()->GetOriginTrackedDeviceInfo( poseData.activeOrigin, &originInfo, sizeof( originInfo ) ) == vr::VRInputError_None
&& originInfo.trackedDeviceIndex != vr::k_unTrackedDeviceIndexInvalid )
{
std::string sRenderModelName = GetTrackedDeviceString( originInfo.trackedDeviceIndex, vr::Prop_RenderModelName_String );
if ( sRenderModelName != m_rHand[eHand].m_sRenderModelName )
{
m_rHand[eHand].m_pRenderModel = FindOrLoadRenderModel( sRenderModelName.c_str() );
m_rHand[eHand].m_sRenderModelName = sRenderModelName;
}
}
}
}
return bRet;
m_pHMD is initalized as follows:
vr::IVRSystem *m_pHMD;
....
m_pHMD = vr::VR_Init( &eError, vr::VRApplication_Background );
I must be doing something wrong because in the following snippet, the if statement is passed only for the first four iterations, which should be a controller, the vive tracker, the headset and the lighthouses. This tells me that I am able to access these states, but I am somehow not able to read the information.
for (int i = 0; i < 1000; i++) {
if (m_pHMD->GetControllerState(i, &state, sizeof(state))) {
dprintf("%d", i);
if (state.ulButtonPressed != 0 || state.unPacketNum != 0 || state.ulButtonTouched != 0) {
dprintf("Some action?");
}
}
I can't imagine its a bug, so my guess is that my configuration is faulty, or I'm doing the wrong query.
Any help is greatly appreciated!
Apparently I was making two mistakes.
Mistake #1 was that I was using the wrong sample file. I used hellovr_opengl from the OpenVr sample folder, but instead hellovr_dx12 was the working solution. It must have a different kind of configration as well, since I copied a function which was working into the hellovr_opengl project and there, it did not work! Then I copied the functions I added to the hellovr_dx12 project and was able to get the controller states of the Vive controller.
However, I wanted to get the states of the Vive Tracker, which didn't work. After some googling I found out about an issue with the current SteamVR driver, so I reverted it back to a beta hoftix, which solved the Vive Tracker issue for me.
You have to call;
vr::VRInput()->SetActionManifestPath

Linear Probing Hash Function not working?

What am i doing wrong with my linear probing function?
bool HashTable_lp::insert( const string & x )
{
// Insert x as active
int currentPos = findPos( x );
if( isActive( currentPos ) )
return true;
array[ currentPos ] = HashEntry( x, ACTIVE );
if( ++currentSize > array.size( ) / 2 )
rehash( );
return false;
}
You generally want a while loop until you find an empty slot. The other problem is you were equating a cell that your string hashes to being active to meaning that the cell contains the same value you are trying to insert. In general, you need to check the value of your key to insert against existing entries. It may be worth making an insert version that does not do this check for cases where the user can guarantee the item is not already in the hash table to avoid these comparisons...
bool HashTable_lp::insert( const string & x )
{
// Insert x as active
int currentPos = findPos( x );
while( isActive( currentPos ) ){
// here key gets out of array[currentPos] the string key
if(key(currentPos)==x) return true; // already in hash
currentPos++; // linearly probe to next guy
}
// at this point we know currentPos is empty
array[ currentPos ] = HashEntry( x, ACTIVE );
if( ++currentSize > array.size( ) / 2 ) // ensure load factor is .5 to guarantee probing works!
rehash( );
return false;
}

Error handling for xml parsing

I'm using tinyxml to parse xml files, and I've found that error handling here lends itself to arrow code. Our error handling is simply reporting a message to a file.
Here is an example:
const TiXmlElement *objectType = dataRoot->FirstChildElement( "game_object" );
if ( objectType ) {
do {
const char *path = objectType->Attribute( "path" );
if ( path ) {
const TiXmlElement *instance = objectType->FirstChildElement( "instance" );
if ( instance ) {
do {
int x, y = 0;
instance->QueryIntAttribute( "x", &x );
instance->QueryIntAttribute( "y", &y );
if ( x >= 0 && y >= 0 ) {
AddGameObject( new GameObject( path, x, y ));
} else {
LogErr( "Tile location negative for GameObject in state file." );
return false;
}
} while ( instance = instance->NextSiblingElement( "instance" ));
} else {
LogErr( "No instances specified for GameObject in state file." );
return false;
}
} else {
LogErr( "No path specified for GameObject in state file." );
return false;
}
} while ( objectType = objectType->NextSiblingElement( "game_object" ));
} else {
LogErr( "No game_object specified in <game_objects>. Thus, not necessary." );
return false;
}
return true;
I'm not huffing and puffing over it, but if anyone can think of a cleaner way to accomplish this it would be appreciated.
P.S. Exceptions not an option.
Edit:
Would something like this be preferable?
if ( !path ) {
// Handle error, return false
}
// Continue
This eliminates the arrow code, but the arrow code kind of puts all of the error logging on one place.
Using return values as error codes just leads to such code, it can't be improved much. A slightly cleaner way would use goto to group all error handling into a single block and to decrease the nesting of blocks.
This does however not solve the actual problem, which is using return values as error codes. In C, there is no alternative, but in C++ exceptions are available and should be used. If they are not an option, you're are stuck with what you have.
You could create a macro for that, which encapsulates the if (!var) { .. return false; } and error reporting.
However, I do not see how this can be improved all that much; its just the way it is. C'est la vie. C'est le code...
I'm not huffing and puffing over it,
but if anyone can think of a cleaner
way to accomplish this it would be
appreciated.
I have replaced the nested ifs with return statements on error (this makes the code "flow down" instead of going "arrow shaped". I have also replaced your do loopps with for loops (so I could understand it better).
Is this what you wanted?
const TiXmlElement *objectType = dataRoot->FirstChildElement( "game_object" );
if ( !objectType ) {
LogErr( "No game_object specified in <game_objects>. Thus, not necessary." );
return false;
}
for(; objectType != 0; objectType = objectType->NextSiblingElement( "game_object" )) {
const char *path = objectType->Attribute( "path" );
if ( !path ) {
LogErr( "No path specified for GameObject in state file." );
return false;
}
const TiXmlElement *instance = objectType->FirstChildElement( "instance" );
if ( !instance ) {
LogErr( "No instances specified for GameObject in state file." );
return false;
}
for(; instance != 0; instance = instance->NextSiblingElement( "instance" )) {
int x, y = 0;
instance->QueryIntAttribute( "x", &x );
instance->QueryIntAttribute( "y", &y );
if ( x >= 0 && y >= 0 ) {
AddGameObject( new GameObject( path, x, y ));
} else {
LogErr( "Tile location negative for GameObject in state file." );
return false;
}
}
}
return true;
I know it is a little late, but I know that QueryIntAttribute returns a value which can be used for error handling in case you want this for your attributes too.
if (instance->QueryIntAttribute("x",&x)!=TIXML_SUCCESS)
cout << "No x value found";