NSData getBytes Randomly Returns Garbage - ios

I'm trying to save and load a custom file format in an iOS app. The format stores various data, but among it is the name a user entered for a map. I found that at random, as I'm trying to read this map name (stored as chars in the file), my NSData object will read garbage. Here is my code for reading the map name (start is already set to the correct start location):
NSData* data = ....;
uint mapNameLength;
char* mapNameChar;
NSString* mapNameString;
[data getBytes:&mapNameLength range:NSMakeRange(start, 4)];
start += 4;
mapNameChar = (char *)malloc(sizeof(char) * mapNameLength);
[data getBytes:mapNameChar range:NSMakeRange(start, mapNameLength)];
mapNameString = [NSString stringWithUTF8String:mapNameChar];
NSLog(#"mapNameLength: %u, mapNameChar: %s, Map name string: %#", mapNameLength, mapNameChar, mapNameString);
As you can see, I am reading the length of the name, then reading that many char values, then converting it into an NSString. Here is the output of the NSLog when it works (I just hit the keyboard a bunch to make a long name):
mapNameLength: 49, mapNameChar: kandfianeifniwbvuandivbwirngiwnrivnwrivnwidnviwdv, Map name string: kandfianeifniwbvuandivbwirngiwnrivnwrivnwidnviwdv
Here is the output of the NSLog when it doesn't work:
mapNameLength: 49, mapNameChar: kandfianeifniwbvuandivbwirngiwnrivnwrivnwidnviwdvfi?p?, Map name string: (null)
Those "?" are actually special characters that don't display here, so I added them. The first is "ETX" and the second is "SOH" in Sublime Text.
To create the file, this is what I am doing:
NSString* mapName = ....;
uint mapNameLength = (uint)mapName.length;
NSMutableData* data = ....;
//...
//Write file type and version here
//...
[data appendBytes:&mapNameLength length:4];
[data appendData:[mapName dataUsingEncoding:NSUTF8StringEncoding]];
//...
//Write other stuff
//...
NSString* path = [FileManager applicationDocumentsDirectory];
path = [path stringByAppendingFormat:#"/%#", fileName];
BOOL success = [data writeToFile:path options:NSDataWritingAtomic error:&error];
I've only written the file once, so I know the data is always the same. Why then, would my data object sometimes get random bytes from it?

I am not certain, however I don't think you are storing a terminating NUL character, so you need to add one to the buffer once you've read the string in:
mapNameChar = (char *)malloc(sizeof(char) * (mapNameLength + 1)); // Add +1
[data getBytes:mapNameChar range:NSMakeRange(start, mapNameLength)];
mapNameChar[mapNameLength] = '\0'; // Terminate with NUL
mapNameString = [NSString stringWithUTF8String:mapNameChar];
Better still forget about malloc() and the C-String and create the NSString directly from the NSData object:
mapNameString = [[NSString alloc] initWithBytes:(const char *)([data bytes]) + start
length:mapNameLength
encoding:NSUTF8StringEncoding];

Related

Objc EXC_BAD_ACCESS when setting a NSString equal to another

I'm having some really REALLY weird issues with NSString. When I read from an input stream and convert the data to a string I'm not able to set anything equal to that string. Here's the code:
NSString *name = r.URL.lastPathComponent;
NSString *data;
NSInputStream *stream = r.HTTPBodyStream;
uint8_t byteBuffer[1];
[stream open];
if (stream)
{
// Get the request body from the stream. Used for setting the file name
if (stream.hasBytesAvailable)
{
NSInteger bytesRead = [stream read:byteBuffer maxLength:4096];
NSString *temp = [[NSString alloc] initWithBytes:byteBuffer length:bytesRead encoding:NSUTF8StringEncoding];
data = temp; // EXC_BAD_ACCESS thrown here
}
}
I need to copy the string over to another string but I can't. Does anyone know why this is happening?
Your byte buffer is one byte big but you're reading 4096 bytes into it. This is likely to trigger a cascading sequence of events that culminates into the crash.

libxslt: xml to html text encoding issue iOS

I am using xslt framework to convert xml to html for iOS project.
I am sending the encoded xml to the xslt framework. But the output it gives is not encoded. So when i try to parse the html, i am getting the parser error.
NSString *xml = #"<div>a<b</div>" // not exact this but its similar in encoding
NSData *xmlMem = [xml dataUsingEncoding:NSUTF8StringEncoding];
NSString* styleSheetPath = [[NSBundle mainBundle] pathForResource:fileName ofType:fileExtension];
xmlDocPtr doc, res;
xsltStylesheetPtr sty;
xmlSubstituteEntitiesDefault(1);
xmlLoadExtDtdDefaultValue = 1;
sty = xsltParseStylesheetFile((const xmlChar *)[styleSheetPath cStringUsingEncoding: NSUTF8StringEncoding]);
doc = xmlParseMemory([xmlMem bytes], [xmlMem length]);
res = xsltApplyStylesheet(sty, doc, nil);
xmlChar* xmlResultBuffer = nil;
xsltSaveResultToString(&xmlResultBuffer, &length, res, sty);
NSString* resultHTML = [NSString stringWithCString: (char *)xmlResultBuffer encoding:NSUTF8StringEncoding];
NSLog(#"Result: %#", resultHTML);
Result: <div>a<b<div>
The result is not an encoded html. Could anyone help me to fix this issue?
The problem is the following: In the course of parsing a string of XML, any entity references are expanded, that is, replaced with the string value they reference.
If your input XML contains entities such as <, they will appear as < as soon as they are parsed - and before the XML can be processed.
To avoid this, just replace & with its entity, too, that is, &. Change
NSString *xml = #"<div>a<b</div>"
to
NSString *xml = #"<div>a&lt;b</div>"
Then, &lt; is resolved to < but no further replacement is applied, since it is not an iterative process.

Converting sqlite3_column_blob to NSString

I have been trying to add sqlite3_column_blob type of value to NSString by this lines of code :
NSUInteger len = sqlite3_column_bytes(compiledStatement, n);
NSData *cData = [[NSData alloc] initWithBytes:sqlite3_column_blob(compiledStatement, n) length:len];
NSString *columnText = [NSString stringWithUTF8String:[cData bytes]];
Here is the BLOB data which i am trying to retrieve from the database :
�PNG
IHDRXXq�04sBIT|d�
�IDATx��{pEǿ� !�f��E���0��#����Q'p#iQ��È�L�P���R`6 F�COJD�q��0 ��\�FbrȁR�������c6��������f�����M��-����n"�~;�p0s��bɶX,c�U^7!�Q!��e�n�2��o�%��#���~3G!�^�X,��<�b��B\S�)ˬ`��Ť*S��#�.�9+c�8ADtN�fd�}����D4��̊�X����u9��f�y̜/_�c�
"J�D�V0�^"�0��h6��Du��,3s83���f"z��j���6M]!V�[q���\��+��O�QUU�K�.*~:���#HH�|�]�F�#tt�'�C�$wU�+<ט�� >}���`��rR�b<�sv��\��'Nb�8~�$��F��h����<z$��1�U{�J�t#'9��~e��X|*�b�I��]��+�:|F��B��6$IB��~xd��>aa����$�/�j��f�H��
rV����ز{>��ju1�Q��'�E�+}Q�/^��&����r�۰Ǿ>����A�:g�S��(��r}Q�Of���
��t��omƶw5Y7�-�$aꔉH�5]��>KD�}1�J`f0#7!DM`7u=p�0Vg��ҥ_��&%,�2^L�#Æ��ʘ�CI�*�8HD���-03�oko��7n"7�mߥ�ѷ���'b��9v:r='���z�������V^ͅ_���E�%z����bU�rt���|"z����y���ݴ��+0��y+.�`��P^^ᬈ�ow�n����S�� %5���[O�t�W������3yB�:]3s["�L;u��g4z�O��uH[�� 2=.�=ƣ>��;x��gA1+/�#JjZ�W����u&DG�����l%�jw�p)03��h�:���/�����^���"<�nl|#O����[$I��jdᮋ��%�7����ŋ���4�eܸq�!O�f���ݙ+;h%��o�z�зOO�I�1����`��g��*�yȫg���pd�x�v]__�=��Ǟ��4?^�()-Gn�,yA�(���wo��A���G��D��Sv&&No'.,9�����J����/�ۥL�0��L����s�m߅ke�4ڻ��.j6�aUV�ΦݢW�D�V!$$D3?$$��L�̞�j6���6H�=��L�u�Vy-r֚��z�7u�K۱K�����u6z���Ꙉ��?�Jpp̚��{�M����Xn�hŸ��x�71k�Sn�8!!!����M����
oۥ�5R�9�`�NB��D4˚VRZ��3��m����<���Ǿ>�s�.�����g#d���о���A��ᴨ�����t������
$I���ۙ:��-I�^$"������<�����_X�G��jL���Vy%ns��C�$!絕��+D�X�Zm�E0sof���E�%-N\���/ߴ
=t�w�h��(�3odf;+���Tc���j#���������Sv�n�]hb����nVRUU�lx�I��x��3=�#�Fc(Lٙ���=��[�N��-
m� ,O��V$?��غ'�#oͪ�׊���5�<Y�O?s0
�WO��i�l���
p|\l��k�*r|\�G����v�j�Ǐ���l~
ߝ�5~q[Q|\,^�{-�ŵb4�����<����nBD�d�6������h��9���J��b�o
�7W����8���b�}�y�,03G1s!T.���O�|�U�����h~``4�"�侻(<~R�4���9
�B,`�T__���2�n���.k��Zi߾V������攨 R���E8�7~8W�r�p��M,{e�W�[?�Ѭ� fs�~�ë����R�l�����L���$i=T�_+�6��K0w�R]bm�`rr�y\�W���%��\���zd����$IkY`"�ff�9�?���!zD޶}�m�JN�:�l�z��b����:�(B����.x0<�RT\���]��m�.d����MEV�Z�"��uX�(]׊�Z+I����_�n�TQS����>ۙ��w~��Z��Y��;?qH���ù"]����fذ�"�9SY��o�{�h��}�'X��OP��:+�Ndo��b�L�^=Iv=}#��еk�|�l(E�Wq����Ů�v7J\#S�pf~���3?�̛�%���ѫʬ<y?��+Z���Q�����:�3�i���zB�/҈h���̊7�J��� �Z/� �:'�������)�u"z����Z����rЪ���$��։F%e(K�� �XSӾ��=��2�����`;��=�w7}�Z�Zٴ� ,��sb�׉}+�t����Z��u�AD)�B�{�[q�Z+"J�ƫ�ڃ����V9��
��
!�~�":�Kx�k��'8��3����`I�V�ۛk0�{S�G���Z�q���6{p%8�,�4�o�42���i>IDC��P�"����FC1���^ڊ���(/ˈh�rs�ڳ���[�{$&�kW���t�a��2��DtEY��+FDq��?�m�U�%��F����c���06ƍMnM8a�X��Q��6��������}�1��־X�����>�ѭ�(j�5m�3�;l���q��s�J"���R��9��C�|��#f�Z.Uf"J%"���#D�(���U��I�����&��9��Ҙ�]"�!���BD5AAAO3�m�=6&�&��*~G1i�x���AAAO����f��$I�)����4�X�$,��̴KSk��ݿy;g����a�"�A�Z<K���&u2ҝ���Q����u6-�<����p�,�����V���s�E�kQ��Dc�¹β55��I#�MD�:���)��ZD�W��uB��5�6f�*I�W9<
)`3?�c�R�RfK�Cʨaf�����盓���8åx ���L���,%� N�k�#D�̼[�ֿ_�Yݢ<��֬v0�3�n���tO�$Ir�ڷOO�7��1rXX'�7�o��yZ����}5���Dc�y=���78�v�o�����c���������A��}�Up�b"����A�a~�(!D=���_��\\���a�m��:��%�&̼S��b��]�f#3��Jd��
6���<u�D�I���^&�����b\94L�/�j� �E�%شy���d�a�1}�����$�����ڋ8p�0�-l�c�I���ô�L���c�A%����tE1���wv�m>�d�|P�5T-��~{P�3,�j�X-�����QY�3��+PU]�˗�#JJ�����DC��бct��#��(DFޏ޽=Z�b悠���:j�r��R��aQ1Ζy|I��b�~o/)���g�h�R�!r��XN'���C\����DtV��M>����Z�9�G����L!D�Ƒ�
�%S.��GN�
�CSW4����vhj�v�!P���?� �kɲIEND�B`�
But every time i am getting nil response although there is a value exist. Rest of the parameter values are coming just i am getting nil response in above value.
Thanks.
The reason you cannot convert that data to a string is because it's a PNG image file:
�PNG
(I assume; I haven't looked at the PNG spec to confirm this, it's just an assumption at this stage).
Finally i got the solution for the above issue which i was facing :
NSData *content = [[NSData alloc] initWithBytes:sqlite3_column_blob(compiledStatement, 2) length:sqlite3_column_bytes(compiledStatement, 2)];
NSString *columnText = [content base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];

How to get a certain bytes length subString from a NSString

Such as I have a NSString is str = #"我就是测试一下" or str = #"我" . And I want to restrict a certain byte length. such as byteLength = 10.
I know the subSrtring is not the str.length=10 How to get a certain bytes length subString from a NSString, thank you
you can use dataUsingEncoding method to get a NSData from NSString. And then use length and bytes property to get the byte length or bytes
Then if the NSData's length > your certain length you should use + (id)dataWithBytes:(const void *)bytes length:(NSUInteger)length; method to get the certain length byte NSData you should be careful that the return NSData may be can not decode by NSString
At last you can use - (id)initWithData:(NSData *)data encoding:(NSStringEncoding)encoding; method to get the result NSString you want
And you can use the code below:
- (NSString *)fetchStringWithOriginalString:(NSString *)originalString withByteLength:(NSUInteger)length
{
NSData* originalData=[originalString dataUsingEncoding:NSUTF8StringEncoding];
const char *originalBytes = originalData.bytes;
//make sure to use a loop to get a not nil string.
//because your certain length data may be not decode by NSString
for (NSUInteger i = length; i > 0; i--) {
#autoreleasepool {
NSData *data = [NSData dataWithBytes:originalBytes length:i];
NSString *string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
if (string) {
return string;
}
}
}
return #"";
}
you can call the above method like this :
NSString* originalString= #"我就是测试一下";
NSString *string = [self fetchStringWithOriginalString:originalString withByteLength:10];
NSData* stringData=[string dataUsingEncoding:NSUTF8StringEncoding];
NSLog(#"10 bytes string : %# ; it only %i bytes",string,stringData.length);
The Result :
Be careful:
the - (id)initWithData:(NSData *)data encoding:(NSStringEncoding)encoding; may be return nil
As apple said:the - (id)initWithData:(NSData *)data encoding:(NSStringEncoding)encoding; Return:
An NSString object initialized by converting the bytes in data into
Unicode characters using encoding. The returned object may be
different from the original receiver. Returns nil if the
initialization fails for some reason (for example if data does not
represent valid data for encoding).
So you should use a for loop to get a nearest length data which can decode by NSSting
Use
[str lengthOfBytesUsingEncoding:NSUTF8StringEncoding]
I think this should work:
NSUInteger bytes = [incomingText lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
if (bytes > MAX_TEXT_BYTES) {
int length = [incomingText length];
int cutoffIndex = (int)(MAX_TEXT_BYTES * (length / bytes));
return [incomingText substringToIndex:cutoffIndex];
}

Replace a Portion of NSMutableData with a NSString

I have some NSMutableData holding some ASCII code.
I would like to replace some bytes in a specific range with other bytes made up of an NSString:
NSString *myString = #"\r"
const char *myChar = [myString UTF8String];
[myData replaceBytesInRange:myRange withBytes:&myChar];
Now, when logging myData I get different values for the exchanged byte every time I run the App! Aren't I supposed to get <0D>?!
What am I doing wrong?

Resources