Viewing contents of IL2CPP's string_t in xcode's debugger - c++

Unity's IL2CPP/LLVM back-end generates cpp files from C#. You can certainly read these files, and drop breakpoints into them to view variables. However C# strings are transcompiled into a custom class called String_t. Xcode doesn't seem to know how to print the inner strings of these classes and I'm not sure how to read the raw bytes.
Here's the String_t definition:
struct String_t : public Object_t
{
// System.Int32 System.String::length
int32_t ___length;
// System.Char System.String::start_char
uint16_t ___start_char;
};
...can anyone figure out how to read the contained string from an Xcode breakpoint?

You can use p il2cpp::utils::StringUtils::Utf16ToUtf8. So if the name of the variable is L_3 for example, then you can do this:
p il2cpp::utils::StringUtils::Utf16ToUtf8(&L_3->___start_char_1)

You can see the string in memory if you right-click the string in the locals window and select View Memory of "*foo". Then the string starts 12 bytes in. Because of IL2CPP's 16bit characters, the string is printed with dots inbetween. This probably doesn't work for unicode characters!
If anyone has a more robust solution I'd love to accept their answer.

Related

C++ Read specific parts of a file with start and endpoint

I am serializing multiple objects and want to save the given Strings to a file. The structure is the following:
A few string and long attributes, then a variable amount of maps<long, map<string, variant> >. My first idea was creating one valid JSONFile but this is very hard to do (all of the maps are very big and my temporary memory is not big enough). Since I cant serialize everything together I have to do it piece by piece. I am planning on doing that and I then want to save the recieved strings to a file. Here is how it will look like:
{ "Name": "StackOverflow"}
{"map1": //map here}
{"map2": //map here}
As you can see this is not one valid JSON object but 3 valid JSONObjects in one file. Now I want to deserialize and I need to give a valid JSONObject to the deserializer. I already save tellp() everytime when I write a new JSONObject to file, so in this example I would have the following adresses saved: 26, endofmap1, endofmap2.
Here is what I want to do: I want to use these addresses, to extract the strings from the file I wrote to. I need one string which is from 0 to (26-1), one string from 26 to(endofmap1-1) and one string from endofmap1 to (endofmap2-1). Since these strings would be valid JSONObjects i could deserialize them without problem.
How can I do this?
I would create a serialize and deserialize class that you can use as part of a hierarchy.
So for instance, in rough C++ psuedo-code:
class Object : public serialize, deserialize {
public:
int a;
float b;
Compound c;
bool serialize(fstream& fs) {
fs << a;
fs << b;
c->serialize(fs);
fs->flush();
}
// same for deserialize
};
class Compound : serialize, deserialize {
public:
map<> things;
bool serialize(fstream& fs) {
for(thing : things) {
fs << thing;
}
fs->flush();
}
};
With this you can use JSON as the file will be written as your walk the heirarchy.
Update:
To extract a specific string from a file you can use something like this:
// pass in an open stream (streams are good for unit testing!)
std::string extractString(fstream& fs) {
int location = /* the location of the start from file */;
int length = /* length of the string you want to extract */;
std::string str;
str.resize(length);
char* begin = *str.begin();
fs->seekp(location);
fs->read(begin, length);
return str;
}
Based on you saying "my temporary memory is not big enough", I'm going to assume two possibilities (though some kind of code example may help us help you!).
possibility one, the file is too big
The issue you would be facing here isn't a new one - a file too large for memory, assuming your algorithm isn't buffering all the data, and your stack can handle the recursion of course.
On windows you can use the MapViewOfFile function, the MSDN has plenty of detail on that. This function will effectively grab a "view" of a section of a file - allowing you to load enough of the file to modify only what you need, before closing and opening a view at a later offset.
If you are on a different platform, there will be similar functions.
possibility two, you are doing too much at once
The other option is more of a "software engineering" issue. You have so much data then when holding them in your std::maps, you run out of heap-memory.
If this is the case, you are going to need to use some clever thinking - here are some ideas!
Don't load all your data into the maps. wherever the data is coming from, take a CRC, Index, or Filename of the data-source. Store that information in the map, and leave the actual "big strings" on the hard disk. - This way you can load each item of data when you need it.
This works really well for data that needs to be sorted, or correlated.
Process or load your data when you need to write it. If you don't need to sort or correlate the data, why load it into a map beforehand at all? Just load each "big string" of data in sequence, then write them to the file with an ofstream.

How do I widen a char in c++

I'm writing a game in c++ using SFML, I found a font that support French characters. However, in the program I read all the text from files to be able to support different languages, but I don't know how to extract the text without errors into a wide strings.
Here's my code:
using namespace std;
using namespace sf;
void SettingsW :: initialize()
{
// using normal characters it reads the files correctly
wifstream settTextFile;
settTextFile.open(pageTextSource);
wstring temp;
getline(settTextFile, temp);
pageTitle.setFont(pageFont);
pageTitle.setString(temp);
getline(settTextFile, temp, L' ');
languageTitle.setFont(pageFont);
languageTitle.setString(temp);
//here is the problem
char g=' ';
ios::widen(g);
getline(settTextFile, temp, ' '));
// I want to use get line with this delimiter and when I use the L the error goes away
//but it doesn't display properly: é is displayed as ã
}
It's not too clear what your problem is. The code you present
shouldn't compile; ios::widen is a member function, and can
only be called on an ios (which is a typedef for
std::basic_ios<char>, of which you have no instance in your
code). Also, ios::widen returns the widened character, except
that ios::widen (as opposed to
std::basic_ios<wchar_t>::widen) doesn't widen, since it returns
achar. If you want to use the character ingthe delimiter
in the last call tostd::getline`, then you could use:
std::getline( settTextFile, tmp, settTextFile.widen( g ) );
(Of course, you should verify that std::getline succeeded
before using the value it read.)
With regards to the “it doesn't display properly”:
you'll have to give more information with regards to how you are
displaying it for us to be sure, but it seems likely to me that
you just haven't imbued your output stream with the same
encoding as the code page of the window (supposing Windows), or
with the encoding of the font used in the window (supposing
Unix). But you'll have to show us exactly what you're
displaying, how you're displaying it, and give us some
information about the environment if you want a complete answer.

Delete content in a text file between two specific characters

I'm making a simple bug tracker and am using a text file as the database. Right now I'm reading in all the information through keys and importing them into specific arrays.
for (int i = 0; i < 5; i++)
{
getline(bugDB, title[i], '#');
getline(bugDB, importance[i], '!');
getline(bugDB, type[i], '$');
getline(bugDB, description[i], '*');
}
Here is what's in my (terribly unreadable) file
Cant jump#Moderate!Bug$Every time I enter the cave of doom, I'm unable
to jump.*Horse too expensive#Moderate!Improvement$The horses cost way
too much gold, please lower the costs.*Crash on startup#Severe!Bug$I'm
crashing on startup on my Win8.1 machine, seems to be a 8.1
bug.*Floating tree at Imperial March#Minimal!Bug$There is a tree
floating about half a foot over the ground near the crafting
area.*Allow us to instance our group#Moderate!Improvement$We would
like a feature that gives us the ability to play with our groups alone
inside dungeons.*
Output:
This works great for me, but I'd like to be able to delete specific bugs. I'd be able to do this by letting the user choose a bug by number, find the corresponding * key, and delete all information until the program reaches the next * key.
I'd appreciate any suggestions, I don't know where to start here.
There is no direct mechanism for deleting some chunk of data from the middle of the file, no delete(file, start, end) function. To perform such a deletion you have to move the data which appears after the region; To delete ten bytes from the middle of a file you'd have to move all of the subsequent bytes back ten, looping over the data, then truncate to make the file ten bytes smaller.
In your case however, you've already written code to parse the file into memory, populating your arrays. Why not just implement a function to write the contents of the arrays back to a file? Truncate the file (open in mode "w" rather than "w+"), loop over the arrays writing their contents back to the file in your preferred format, but skip the entry that you want to delete.
its only possible by manually copying the data from input file to output file and leaving out the entry you want to delete.
but: i strongly encourage the usage of some small database for keeping the informations (look at sqlite)
Also its a bad bugtracker if solving the bug means "delete it from database" (its not even is a tracker). give it a status field (open, refused, duplicate, fixed, working, ...).
Additional remarks:
use one array that keeps some structure with n informations and not n arrays.
please remind that someone may use your delimiter characters in the descriptions (use some uncommon character and replace its usage in saved text)
explanation for 1.:
instead of using
std::vector<std::string> title;
std::vector<int> importance;
std::vector<std::string> description;
define a structure or class and create a vector of this structure.
struct Bug{
std::string title;
int importance; // better define an enum for importance
std::string description;
};
std::vector<Bug> bugs;

Pass a wxString into a printf-style varargs function

I am learning to code in C using K&R II. I am tired of console apps and decided to get into a GUI environment. Decided to use Code Blocks and wxWidgets. All is installed properly and working. [Windows 7 x86, Code Blocks 13.12, wxWidgets 3.0.0]
I am following the Tutorials on WxWidgets. I am in Tutorial 9. I have it working, finally; there are mistakes in the instructions.
I modified my app to have 2 text boxes and a button vs one text box for the output and one combo box for the input.
Visual C++ environment is totally foreign to me.
For the Button click I would like instead of printing, "O brave new world!\n",
I would like to read what has been entered in textbox1 and print it into textbox2.
The instruction:
wxString Text = TextCtrl1->GetValue();
gets the string that has been entered in textbox1
I have a call to the function
void printg(char *fmt, ...);
I need to know how/what to change the ... argument to so it will passes the wxString Text in the form of an array, I think, to that printg function. I am sure the first thing I need to do is change the Text string to an array, or some way to pass the string itself.
UPDATE 01/08/13 3:35 PM
I cut the code from the Textbox Enter event and pasted it into the ButtonClick event and now I can get the text in Box one to box two.
Now, I need a way to pass the text from textbox 1 to one of my C files, do whatever the exercise is about and pass it back to the click event to be passed to the printg function.
NOTE: I see confusion about printg. I think it is a feature of wxWidgets that lets you print back to a GUI form rather than a console as printf does. It works.
I would put the code on here, but I do not know how. Tried before and get a message about it not being formatted properly.
Thanks for the replies.
Text.ToUTF8().data() gives you const char *
Also if you only want char* instead of const char * you can use const_cast<char *>(Text.ToUTF8().data())
The most convenient thing to do is to use wx equivalents of standard functions, i.e. wxPrintf() in this case, because they allow you to pass wxString (and also std::string, std::wstring, char* and wchar_t*) objects directly, without doing anything special. So you could simply write
wxString s = ...;
wxPrintf("My string is %s\n", s);
OTOH using either printf() or wxPrintf() is generally not very useful in GUI applications, you probably want wxLogMessage() or something similar.
If you have a string: char *str = {"this is my string"};
Then you can use printf() like this:
printf("%s\n", str);
Note, there is no printg() in the C language. And the prototype of the printf() statement allows for multiple arguments to be passed as long as there is a format specifier for each argument. For example, this shows 3 format specifiers, and three arguments:
printf("%s %d %f\n", str, 10, 13.5);
The "..." argument is called the ellipse argument. It's covered in the K&R book, section 7.3 (in my edition anyway). It can have 0 or more arguments in it, as described by the *fmt argument.
If you already have a string ready, just call it like this:
printf("%s",str);

C++ character encoding when converting from string to const char* for Ruby FFI interface

I am using an external C++ lib that does some HTTPS communication and provides the XML server response. On serverside the response is encoded via ISO-8859-15 and I get a std::string that represents that response out of the API. When I print it out / write it to a file it looks proper.
The std::string and an int error code have to be passed to my external caller. So I return both values inside a struct:
extern "C" {
struct FoobarResponse {
const char* responseText;
int returnCode;
};
}
Unfortunately I have to convert the std::string response into a const char* C-style string representation with help of std::c_str() before. Reason: My caller is a Ruby script making use of Ruby FFI to communicate with my C++ lib, and interlanguage type conversion here is Ruby::string -> C::const char*.
Interesting here: If I std::cout the converted string after I put it into the struct, it is still ok.
The problem: When handling the server response on Ruby side, it is broken. Instead of the original answer like:
<?xml version="1.0" encoding="ISO-8859-15"?>
<Foobar xmlns="http://www.foobar.com/2012/XMLSchema">
...
</Foobar>
I receive a string obviously containing non printable characters which is always broken at the beginning and at the end.
?O[
l version="1.0" encoding="ISO-8859-15"?>
<Foobar xmlns="http://www.foobar.com/2012/XMLSchema">
</Fo??
In fact the string contains linebreaks, carriage returns and tabs at least, maybe more.
I tried to :force_encoding the string on Ruby side as ASCII-8BIT, ISO-8859-15 and UTF-8, no change.
I tried to base64 encode on C++ side before putting the string into the struct and base64 decode on Ruby side using this code, no change.
I had countless attepts to convert the string using Iconv as well, no change.
I also tried to remove non printable characters from the string before putting it into the struct, but I failed on that.
I have no idea what is going on here and running out of options.
Can someone point me into the right direction?
Regards
Felix
The value returned by c_str() is destroyed as soon as the std::string goes out of scope.
If you intend to pass this value to your script you should allocate memory and copy the string into your newly allocated space. See this example: http://www.cplusplus.com/reference/string/string/c_str/
You should also ensure the ruby script will correctly release memory.
I think this is what is explained there: https://github.com/ffi/ffi/wiki/Examples.
Example with a struct passed to Ruby from C:
https://github.com/ffi/ffi/wiki/Examples#-structs