Using wcstod to convert zero value - c++

Am using wcstod() to convert to numeric type text data which I read from an XML file:
double x;
BSTR name;
MSXML::IXMLDOMNodeListPtr theList;
MSXML::IXMLDOMNodePtr theItem;
//Some XML API here...
theItem = theList->Getitem(0);
theItem->get_text(&name);
x = wcstod(name,NULL);
the problem is that this function returns NULL upon failure, but sometimes I do want to read and convert the valid string L"0".
Is there a workaround for this?

You can use std::stod which will throw exception if the function fails.
Make sure BSTR is initialized to NULL. Add error check for Getitem and get_text
#include <string>
BSTR name = nullptr;
...
double x = 0;
if(name)
{
try
{
x = std::stod(name);
}
catch(...)
{
//error ...
}
}

Related

Error on 'nlohmann::json::from_bson()': syntax error while parsing BSON cstring

I have a binary std::string (length = 560):
01111011001000100111010101110011011001010111001001101110011000010110110101100101001000100011101000100000001000100100110001101001011011100110111101111001001000100010110000100000001000100111000001100001011100110111001101110111011011110111001001100100001000100011101000100000001000100011000100110010001100110011010000110101001101100010001000101100001000000010001001100101011011010110000101101001011011000010001000111010001000000010001001101100011010010110111001101111011110010100000001101101011000010110100101101100001011100110001101101111011011010010001001111101
When I convert it to ASCII (using online websites), I get the JSON string I want:
{"username": "Linoy", "password": "123456", "email": "linoy#mail.com"}
I want to convert the binary std::string to a nlohmann::json object, so I use nlohmann::json::from_bson().
To do it, I need to send to from_bson() function a std::vector<uint8_t>
So I convert the std::string to the needed std::vector<uint8_t>:
using JSON = nlohmann::json;
std::vector<uint8_t> vec;
vec.assign(to_convert.begin(), to_convert.end());
JSON json_object = JSON::from_bson(vec);
The problem is I get an error on the when calling from_bson(), is that I get an error:
[json.exception.parse_error.110] parse error at byte 561: syntax error while parsing BSON cstring: unexpected end of input
**That's it. That's my problem. Can someone help me?**
**If you wanna see where is the exact error, follow this:**
I tried to place some breakpoints, and found out that the code is throwing an exception in json.hpp: line 24338, sax_parse() function (line 10 in this codeblock):
template<typename InputType>
JSON_HEDLEY_WARN_UNUSED_RESULT
static basic_json from_bson(InputType&& i,
const bool strict = true,
const bool allow_exceptions = true)
{
basic_json result;
detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
auto ia = detail::input_adapter(std::forward<InputType>(i));
const bool res = binary_reader<decltype(ia)>(std::move(ia)).sax_parse(input_format_t::bson, &sdp, strict);
return res ? result : basic_json(value_t::discarded);
}
When going deeper, inside sax_parse() function, it throw the exception in json.hpp: line 7743, parse_bson_internal() function (line 10 in this codeblock):
bool sax_parse(const input_format_t format,
json_sax_t* sax_,
const bool strict = true,
const cbor_tag_handler_t tag_handler = cbor_tag_handler_t::error)
{
sax = sax_;
bool result = false;
switch (format)
{
case input_format_t::bson:
result = parse_bson_internal();
break;
When going deeper, inside parse_bson_internal(), it throw the exception in json.hpp: line 7803, pars_bson_element_list(false) function (line 9 in this codeblock):
bool parse_bson_internal()
{
std::int32_t document_size{};
get_number<std::int32_t, true>(input_format_t::bson, document_size);
if (JSON_HEDLEY_UNLIKELY(!sax->start_object(std::size_t(-1))))
{
return false;
}
if (JSON_HEDLEY_UNLIKELY(!parse_bson_element_list(/*is_array*/false)))
{
return false;
}
return sax->end_object();
}

Error handling of returning values from DLL

Using C++ I'm working on a method in DLL which returns a value of temperature from a device.
I would like to return as well an error status of the device in case if temperature can not be read. This way I want to add kind of error handling to avoid calling extra methods to get device status.
So I can not return a wrong temperature value if it can not be properly read, e.g. if device is not initialized I could return -1.0 or -2.0 but it can be interpreted as the temperature.
Also I want that calling of this method and using this DLL will be compatible with another programming languages such as Pascal/Delphi, Python etc.
in Java I would make a jar with the such method:
public float getTemperature() throws Exception{
float temperature;
try{
temperature = ...;
return temperature;
}catch(Exception E){
throw new Exception("Device not initialized...")
}
}
would it be correct to implement this in C++ the following way where temperature will be returned by parameter and the negative return values of method contain error codes:
declaration:
extern "C" MYDLL int getTemperature(float*);
implementation:
int getTemperature(float* temp)
{
if (device_not_ready)
{
*temp = 0;
return -1;
}
if (device_has_error)
{
*temp = 0;
return -2;
}
float temperature = device_temperature;
*temp = temperature;
return 1;
}

C++ Bad access when assigning an element to map value

So the question explains the problem...
Background:
I'm trying to solve this problem from HackerRank.
It's basically an html tag parser. Valid input guaranteed, attributes are strings only.
My Approach
I created a custom Tag class that can store a map<string,Tag> of other Tag's, as well as a map<string,string> of attributes. The parsing seems to be working correctly.
The Problem
During the querying part, I get a BAD_ACCESS error on the following query/html combo:
4 1
<a value = "GoodVal">
<b value = "BadVal" size = "10">
</b>
</a>
a.b~size
The error occurs when I try to access the b Tag from a. Specifically, it's in the t=t.tags[tag_name], Line 118 below.
Code
#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
#include <sstream>
#include <map>
#include <stack>
using namespace std;
class Tag {
public:
Tag(){};
Tag(string name):name(name){};
string name;
map<string,Tag> tags = map<string, Tag>();
map<string,string> attribs=map<string,string>();
};
int main() {
int lines, queries;
std::cin>>lines>>queries;
std:string str;
getline(cin, str);
stack<string> open;
auto tags = map<string, Tag>();
for (int i = 0; i < lines; i++) {
getline(cin, str);
if (str.length()>1){
// If it's not </tag>, then it's an opening tag
if (str[1] != '/') {
// Parse tag name
auto wordidx = str.find(" ");
if (wordidx == -1) {
wordidx = str.length()-1.f;
}
string name = str.substr(1,wordidx-1);
auto t = Tag(name);
string sub = str.substr(wordidx);
auto equalidx=sub.find("=");
// Parse Attributes
while (equalidx != std::string::npos) {
string key = sub.substr(1,equalidx-2);
sub = sub.substr(equalidx);
auto attrib_start = sub.find("\"");
sub = sub.substr(attrib_start+1);
auto attrib_end = sub.find("\"");
string val = sub.substr(0, attrib_end);
sub = sub.substr(attrib_end+1);
t.attribs[key] = val;
equalidx=sub.find("=");
}
// If we're in a tag, push to that, else push to the base tags
if (open.size() == 0) {
tags[name] = t;
} else {
tags[open.top()].tags[name]=t;
}
open.push(name);
} else {
// Pop the stack if we reached a closing tag
auto wordidx = str.find(">");
string name = str.substr(2,wordidx-2);
// Sanity check, but we're assuming valid input
if (name.compare(open.top())) {
cout<<"FUCK"<<name<<open.top()<<endl;
return 9;
}
open.pop();
}
} else {
std::cout<<"FUCK\n";
}
}
//
// Parse in queries
//
for (int i = 0; i < queries; i++) {
getline(cin, str);
Tag t = Tag();
bool defined = false;
auto next_dot = str.find(".");
while (next_dot!=string::npos) {
string name = str.substr(0,next_dot);
if (defined && t.tags.find(name) == t.tags.end()) {
//TAG NOT IN T
cout<<"Not Found!"<<endl;
continue;
}
t = !defined ? tags[name] : t.tags[name];
defined = true;
str = str.substr(next_dot+1);
next_dot = str.find(".");
}
auto splitter = str.find("~");
string tag_name = str.substr(0,splitter);
string attrib_name = str.substr(splitter+1);
if (!defined) {
t = tags[tag_name];
} else if (t.tags.find(tag_name) == t.tags.end()) {
//TAG NOT IN T
cout<<"Not Found!"<<endl;
continue;
} else {
t = t.tags[tag_name];
}
// T is now set, check the attribute
if (t.attribs.find(attrib_name) == t.attribs.end()) {
cout<<"Not Found!"<<endl;
} else {
cout<<t.attribs[attrib_name]<<endl;
}
}
return 0;
}
What I've tried
This is fixed by just defining Tag x = t.tags[tag_name]; in the line above as a new variable, and then doing t = x; but why is this even happening?
Also, the following query also then fails: a.b.c~height, but it fails on Line 99 when it tried to get a.tags["b"]. No idea why. I was gonna just go with the hacky fix above, but this seems like a big core issue that i'm doing wrong.
I would suggest running this on an IDE and verifying that the parsing is indeed correct.
t=t.tags[tag_name]
This expression is unsafe because you are copy-assigning an object that is owned by that object over the owning object.
Consider what happens on this line:
The map lookup is performed and returns a Tag&.
You try to copy-assign this to t, invoking the implicit copy-assigment operator.
This operator copy-assigns t.tags from the tags attribute of the copy source -- which lives in t.tags.
The result is that the object you're copying into t is destroyed in the middle of that copy. This causes undefined behavior, and an immediate crash is honestly the best possible outcome as it told you exactly where the problem was. (This kind of problem frequently manifests at some point later in the program, at which point you've lost the state necessary to figure out what caused the UB.)
One workaround would be to move the source object into a temporary and then move-assign that temporary over t:
t = Tag{std::move(t.tags[tag_name])};
This lifts the data we want to assign to t out of t before we try to put it in t. Then, when t's assignment operator goes to replace t.tags, the data you're trying to assign to t doesn't live there anymore.
However, this overall approach involves a lot of unnecessary copying. It would be better to declare t as Tag const *t; instead -- have it be a pointer to a tag. Then you can just move that pointer around to point at other tags in your data structure without making copies.
Side note: I just did this problem the other day! Here's a hint that might help you simplify things: do you actually need a structure of tags? Is there a simpler type of lookup structure that would work instead of nested tags?

Embarcadero: How to use TBase64Encoding's EncodeBytesToString method

I am attempting to convert an array of bytes to a base64 encoded String using the EncodeBytesToString method of the TBase64Encoding class. The documentation for EncodeBytesToString states:
"Returns a string with the input array of bytes encoded up to the specified number of bytes."
Therefore, I attempted to encode my byte array like so:
TFile * File = new TFile();
TBytes Bytes = File->ReadAllBytes("D:\\Sample.pdf");
TBase64Encoding * Encoder = new TBase64Encoding();
String EncodedBytes = Encoder->EncodeBytesToString(Bytes, Bytes.Length);
However, I get the following error:
E2285 Could not find a match for 'TNetEncoding::EncodeBytesToString(TByteDynArray,int)'
I am confused, as the documentation seems to say that I should pass a TBytes object and an int into this function. What am I missing here?
Try this:
//------------------------------------------------------------------------------
String __fastcall BytesToBase64( TByteDynArray _ArrayIn )
{
TBase64Encoding * Encoding = new TBase64Encoding( 64, '\n' );
String Result = Encoding->EncodeBytesToString( &_ArrayIn[0], _ArrayIn.High );
delete Encoding;
return Result;
}
//------------------------------------------------------------------------------
TByteDynArray __fastcall Base64ToBytes( String _64String )
{
TByteDynArray My64Bytes = _64String.BytesOf();
return TNetEncoding::Base64->Decode(&My64Bytes[0], My64Bytes.High);
}
//------------------------------------------------------------------------------
System.NetEncoding.TNetEncoding provides the static property Base64 to retrieve an instance of TNetEncoding for base64 encoding.
So this will also work:
String __fastcall BytesToBase64(TByteDynArray _ArrayIn)
{
return TNetEncoding::Base64->EncodeBytesToString(&_ArrayIn[0], _ArrayIn.High);
}

Create a function to get a username using a try and catch method in C++

I'm trying to create a function to get a username using a try and catch method in C++. Unfortunately this code doesn't work, and my application closes when it tries to run.
QString UserInfo::getFullUserName()
{
DBG_ENTERFUNC(getFullUserName);
QString result;
qDebug("trying to get the username");
try
{
struct passwd fullUserData=*getpwnam(getUserName().toLatin1());
result = fullUserData.pw_gecos;
// it is the first of the comma seperated records that contain the user name
result = result.split(",").first();
if (result.isEmpty())
{
result = getUserName();
}
}
catch (...)
{
qDebug("exception caught");
}
qDebug() << result;
#endif
DBG_EXITFUNC;
return result;
}
The problem occurs in this line of code as I have placed prints after it that are never reached.
struct passwd fullUserData=*getpwnam(getUserName().toLatin1());
Does anyone know what is the issue here?
*Edit--------
Here is my function getUserName()
QString UserInfo::GetUserName()
{
DBG_ENTERFUNC(GetUserName);
QString result;
foreach (QString environmentEntry, QProcess::systemEnvironment())
{
QString varName = environmentEntry.section('=',0,0);
QString varValue = environmentEntry.section('=',1,1);
if (varName == "USER" || varName == "USERNAME")
{
result = varValue;
}
}
DBG_EXITFUNC;
return result;
}
getpwnam() returns NULL when the username was not found. You are potentially dereferencing a NULL pointer.
*getpwnam(getUserName().toLatin1());
// ^ potential NULL pointer deref
Always check before deferencing a potentially invalid pointer:
struct passwd *fullUserData = getpwnam(getUserName().toLatin1());
// ^ note pointer
if (fullUserData != NULL) {
result = fullUserData->pw_gecos;
// ^^ fullUserData is a struct pointer
} else {
// throw Exception
}
If this is confusing to you, you might want to read up on C++ and pointers.