I want to hash a file (using SHA1 at the moment). Here is the function:
static inline __attribute__((always_inline)) NSString *SHA1String(NSData *data) {
uint8_t digest[CC_SHA1_DIGEST_LENGTH];
CC_SHA1(data.bytes, (CC_LONG)data.length, digest);
NSMutableString *output = [NSMutableString stringWithCapacity:CC_SHA1_DIGEST_LENGTH * 2];
for (int i = 0; i < CC_SHA1_DIGEST_LENGTH; i++) {
[output appendFormat:#"%02x", digest[i]];
}
return output;
}
And here are the two different methods of loading the data:
CFURLRef filePath = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, CFSTR("/path/to/file"), kCFURLPOSIXPathStyle, false);
CFDataRef cfFileData = CFURLCreateData(kCFAllocatorDefault, filePath, kCFStringEncodingUTF8, false);
NSString *cfFileHash = SHA1String((__bridge NSData *)cfFileData);
NSData *fileData = [NSData dataWithContentsOfURL:[NSURL fileURLWithPath:#"/path/to/file"]];
NSString *fileHash = SHA1String((__bridge NSData *)fileData);
NSLog(#"Hashes: %# - %#", cfFileHash, fileHash);
The hashes differ and I wonder what is causing this. I'd like to use the CoreFoundation API, but if the file hash differs, that'd be bad.
I use another file manager to view the sha1 of the file and it matches the one from NSData.
Any insights appreciated.
Related
I have a function that gets all contents of directory whether files or directories and I am using contentsOfDirectoryAtPath to collect the content of a directory then I save the names of files/directories into a container called contentsStore which accepts key&value items of UTF-16 string char16_t. look at the following code to make your vision clear:
NSArray *dirContents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:_dirPath error:nil];
for(unsigned int i= 0; i< [dirContents count]; i++){
if(isDir){
// `contentsStore` is key&value container that accepts utf-16 string (char16_t)
contentsStore.Add([[dirContents objectAtIndex:i] UTF8String], "directory");
} else {
contentsStore.Add([[dirContents objectAtIndex:i] UTF8String], "file");
}
}
Note that I don't post the entire code because it's big but I just added the important parts that related to the problem. Also, I am using Objective-C just as a bridge to achieve my goal to use Cocoa in macOS but the main language that I use is C++, so, the entire code is a combination of C++/Objective-C.
How to make the objectAtIndex method to output the item's content as UTF-16 char16_t?
the following will give you an idea. The [Filemanager defaultmanager] is actually supporting your task. You can convert the path to C-string and convert then into string of char16_t aka basic_string<char16_t>.
NSString *_dirPath = [[NSBundle mainBundle] bundlePath];
NSError *error = nil;
NSFileManager *manager = [[NSFileManager defaultManager] init];
NSArray *dirContents = [manager contentsOfDirectoryAtPath:_dirPath error:&error];
if (!error && dirContents.count ) {
for(unsigned int i = 0; i < [dirContents count]; i++){
NSString *path = [dirContents objectAtIndex:i];
BOOL isDir;
std::string usingkey = "file";
if ([manager fileExistsAtPath:path isDirectory:&isDir] && isDir) {
usingkey = "directory";
}
const char *fileRepresentation = [manager fileSystemRepresentationWithPath:path];
// function declared below..
std::u16string char16string = to_utf16(fileRepresentation);
// and use it to store your C++ storageObject, value&key pair
// don't know of what datatype is usingkey in your source
// just assumed std::string
contentsStore.Add(char16string, usingkey);
}
}
you will have to include the following in your .mm implementation
#include <string>
#include <codecvt>
#include <iostream>
#implementation Yourclassname
//std::u16string is same as basic_string<char16_t>
std::u16string to_utf16( std::string str )
{ return std::wstring_convert< std::codecvt_utf8_utf16<char16_t>, char16_t >{}.from_bytes(str); }
#end
Thanks in advance for taking your time out for reading and hoping to assist me. I am relatively new to coding and the current problem I am facing is;
I have built a sqlite3 database, with three columns which are respectively stored as; string, float and an int. When trying to read and represent the columns, I am having trouble in finding a method in order to represent the float and int values.
The three properties which are stores in the database are set as;
#property (nonatomic, strong) NSString *name;
#property (nonaomtic, strong) NSNumber *price;
#property (nonaomtic, strong) NSNumber *quantity;
I'm not sure if maybe changing the latter two properties into float and int would make a difference?
However, the main confusion for me lies in the following code I have made in order to call on the data base;
-(void)readDataFromDatabase{
[self.stock removeAllObjects];
sqlite3 *database;
if (sqlite_open([self.databasePath UTF8String], &database) == SQLITE_OK) {
char *sqlStatement = "select * from entries";
sqlite3_stmt *compiledStatement;
if (sqlite3_prepare_v2(database, sqlStatement, -1, &compiledStatement, NULL) == SQLITE_OK){
while(sqlite3_step(compiledStatement) == SQLITE_ROW{
char *n = sqlite3_column_text(compiledStatement, 1);
char *p = sqlite3_column_int(compiledStatement, 2);
chat *q = sqlite3_column_int(compiledStatement, 3);
NSString *name = [NSString stringWithUTF8String:n];
NSNumber *price = [NSString stringWithUTF8String:p];
NSNumber *quantity = [NSString stringWithUTF8String:q];
Data *data = [[Data alloc] initWithData:name thePrice: price theQuantity:quantity];
[self.stock addObject:data];
}
}
sqlite3_finalize(compiledStatement);
}
sqlite3_close(database);
}
My common sense tells me the problem lies in this section;
NSString *name = [NSString stringWithUTF8String:n];
NSNumber *price = [NSString stringWithUTF8String:p];
NSNumber *quantity = [NSString stringWithUTF8String:q];
I'm not sure how I should approach the NSNumber? I'm aware the NSString stringWithUTF8String is not correct, but I don't know the equivalent for NSNumber.
I would really appreciate any insight and help on this matter.
Thank you!
You are on the right track with what you've mentioned for float and int. Float does not need to be referenced like NSString because it's size does not vary between 32-bit and 64-bit systems. If your integer is larger then I would recommened using NSInteger for that value:
char *n = sqlite3_column_text(compiledStatement, 1);
float p = sqlite3_column_text(compiledStatement, 2);
int q = sqlite3_column_text(compiledStatement, 3);
NSString *name = [NSString stringWithUTF8String:n];
float price = p;
NSInteger quantity = q;
Note: You don't the * for the float or int values, since they are not pointers.
You might even be able just to do (If you are already declaring the properties in your header):
name = [NSString stringWithUTF8String:sqlite3_column_text(compiledStatement, 1)];
price = sqlite3_column_text(compiledStatement, 2);
quantity = sqlite3_column_text(compiledStatement, 3);
To check the values you can use NSLog:
NSLog(#"%# %.02f %li", name, price, quantity);
For completeness sake, if you wanted to make the float and int into NSNumber:
NSString *name = [NSString stringWithUTF8String:n];
NSNumber *price = [NSNumber numberWithFloat:p];
NSNumber *quantity = [NSNumber numberWithInt:q];
With the properties in your header declared:
name = [NSString stringWithUTF8String:n];
value = [NSNumber numberWithFloat:p];
quantity = [NSNumber numberWithInt:q];
NSLog(#"%# %#.02f %#", name, price, quantity);
There are multiple ways to get your result, and that's what makes Objective-C quite flexible.
I am writing an Objective-C wrapper for a C++ class. On the OC side I have to take an NSData (read from a json file) get a list out from it and convert that to std::vector< std::string >. Here is my code so far (in an mm file):
NSData *input = [NSData dataWithContentsOfFile:[NSString stringWithUTF8String:"1455469592904_acceldata742283.json"]];
NSError* error;
NSDictionary* jsonArray = [NSJSONSerialization JSONObjectWithData:input options:NSJSONReadingMutableContainers error:&error];
NSMutableArray *accdata = [jsonArray valueForKeyPath:#"data.accelerometer" ];
int size = [accdata count];
vector<string> cppAccdata;
for (int i = 0; i< size; i++){
//~ cppAccdata.push_back();
NSLog(#"%#",[accdata objectAtIndex:i]);
}
The accdata speaking loosely is a list of strings. The json file basically looks like this (with more lines but that's beside the point):
{
"data" : {
"accelerometer" : [
"1455463005.714 -8.311620700836182 -3.969735990142822 -3.737648066711425",
"1455463005.724 -8.256703700256347 -4.017769660949707 -3.680336864471435" ] }}
The output of the code is:
2016-02-15 14:18:16.212 test-OC[10300] 1455463066.241 -7.960421244812011 -4.400093738555908 -3.746177410125732
2016-02-15 14:18:16.212 test-OC[10300] 1455463066.261 -8.019677735900878 -4.377498460388184 -3.634847032928467
2016-02-15 14:18:16.212 test-OC[10300] GSCBufferString
Technically I need to convert [accdata objectAtIndex:i] to an std::string, which I guess would work through a C const char *, but I have not been able to find anything on converting a GSCBufferString into anything. How can I achieve this? There also might be a more elegant way to loop through accdata.
NSArray *accdata = [jsonArray valueForKeyPath:#"data.accelerometer" ];
vector<string> cppAccdata;
for (NSString *str in accdata) {
cppAccdata.push_back(str.UTF8String);
}
Try this:
NSArray *jsonArray;
NSArray *accData = [jsonArray valueForKeyPath:#"data.accelerometer"];
vector<string> cppAccdata;
for (NSString *str in accData){
std::string *accString = new std::string([str UTF8String]);
cppAccdata.push_back(*accString);
}
The two answer proposed were correct in the way of doing the conversion, but the loop syntax didn't compile. This workaround works though:
int size = [accdata count];
vector<string> cppAccdata;
for (int i = 0; i< size; i++){
cppAccdata.push_back([[accdata objectAtIndex:i] UTF8String]);
}
I have a new question here! As the real problem was not in the C++ conversion but rather that I need to convert the returned string data bytes into a CGImageRef. Anybody know how to do that please go to that link to answer the follow on to this question.
Thank you.
OK. Instead of muddying the question with protobuf stuff, I have simplified my test method to simulate the call that would be made to the protobuf stuff.
This test method does the following two parts. Part 1 takes a UIImage and converts it into a std::string.
take a UIImage
get the NSData from it
convert the data to unsigned char *
stuff the unsigned char * into a std::string
The string is what we would receive from the protobuf call. Part 2 takes the data from the string and converts it back into the NSData format to populate a UIImage. Following are the steps to do that:
convert the std::string to char array
convert the char array to a const char *
put the char * into NSData
return NSData
- (NSData *)testProcessedImage:(UIImage *)processedImage
{
// UIImage to unsigned char *
CGImageRef imageRef = processedImage.CGImage;
NSData *data = (NSData *) CFBridgingRelease(CGDataProviderCopyData(CGImageGetDataProvider(imageRef)));
unsigned char *pixels = (unsigned char *)[data bytes];
unsigned long size = [data length];
// ***************************************************************************
// This is where we would call transmit and receive the bytes in a std::string
// ***************************************************************************
// unsigned char * to string
std::string byteString(pixels, pixels + size);
// string to char array to const char *
char myArray[byteString.size()+1];//as 1 char space for null is also required
strcpy(myArray, byteString.c_str());
const char *bytes = (const char *)myArray;
// put byte array back into NSData format
NSUInteger usize = byteString.length();
data = [NSData dataWithBytes:(const void *)bytes length:sizeof(unsigned char)*usize];
NSLog(#"examine data");
return data;
}
The is the code for when the data is returned:
NSData *data = [self.messageCommand testProcessedImage:processedImage];
// But when I try to alloc init a UIImage with the data, the image is nil
UIImage *image = [[UIImage alloc] initWithData:data];
NSLog(#"examine image");
Everything seems to go as planned until I try to create the UIImage with the data. Alloc initing the UIImage with that data returns nil. There must be some type of conversion that will make this work.
OK, so the problem is most likely with the repeated conversions between Objective-C, C and C++ data structures. Overall, you need to make sure to initialize the string as a byte array rather than a textual C string, and you want to get back the raw bytes without a null terminator. I think this will preserve the data correctly:
- (void)onDataReceived:(NSNotification *)note {
if ([note.name isEqualToString:#"DataReceived"]) {
NSDictionary *userData = note.userInfo;
NSData *imageData = [userData objectForKey:#"ImageData"];
// Note the two-argument string constructor -- this is necessary for non-textual data!
std::string byteString = std::string(static_cast<const char*>([imageData bytes]), imageData.length);
// We get the image back as a std::string
std::string imageStr = [self.message parseMessage:byteString ofSize:byteString.size()];
NSLog(#"examine imageStr");
// We get the data from the std::string
char *imageCStr = new char[imageStr.size()];
imageStr.copy(imageCStr, imageStr.size());
NSData *data = [NSData dataWithBytes:imageCStr length:imageStr.size()];
delete[] imageCStr;
// But when I try to alloc init a UIImage with the data, the image is nil
UIImage *image = [[UIImage alloc] initWithData:data];
NSLog(#"examine image");
}
}
I tried the answer. There were some minor changes I needed to make to get rid of errors. Also, I had changed some variable names to minimize confusion. This is still returning nil for the UIImage.
- (void)onObjectReceived:(NSNotification *)note {
if ([note.name isEqualToString:#"ObjectReceived"]) {
NSDictionary *userData = note.userInfo;
NSData *objectData = [userData objectForKey:#"ObjectData"];
// Added this because bytes is used below. Or did you mean something else?
const char *bytes = (const char *)[objectData bytes];
// Note the two-argument string constructor -- this is necessary for non-textual data!
std::string byteString = std::string(static_cast<const char*>(bytes), objectData.length);
// This is an out parameter in the parseMessage method.
long unsigned int *msgSize = (long unsigned *)malloc(sizeof(long unsigned int));
// We get the image back as a std::string
std::string imageStr = [self.message parseMessage:byteString outMsgSize:msgSize];
NSLog(#"examine imageStr");
// We get the data from the std::string
char *imageCStr = new char[imageStr.size()];
imageStr.copy(imageCStr, imageStr.size());
NSData *data = [NSData dataWithBytes:imageCStr length:imageStr.size()];
delete[] imageCStr;
// But when I try to alloc init a UIImage with the data, the image is nil
UIImage *image = [[UIImage alloc] initWithData:data];
NSLog(#"examine image");
}
}
I tried removing everything in between and it worked. Here's the code:
- (NSData *)testProcessedImage:(UIImage *)processedImage
{
// UIImage to unsigned char *
CGImageRef imageRef = processedImage.CGImage;
NSData *data1 = (NSData *) CFBridgingRelease(CGDataProviderCopyData(CGImageGetDataProvider(imageRef)));
UIImage *image = [UIImage imageWithCGImage:imageRef];
This tells me that the NSData dataWithBytes is not going to work, because I am using a CGImageRef. My image is raw data coming from the camera (not a PNG or JPEG).
I found this answer on SO that was helpful. The asker even posted this comment, "It looks quite simple to wrap (the) data in a CFData object, and then CGDataProviderCreateWithCFData."
I found another answer on SO that was also helpful. It shows how to create a CFDataRef using the string.
There is a lot of helpful information out there but still not finding what I need. I'm going to ask another question and reference it back here when I get an answer.
Thank you.
I uses ARC
NSAttributedString * arString = [self asSchedule:arTimes];
self.lblTimeLeft.attributedText = arString;
Not much information is given. It goes straight to main
int main(int argc, char *argv[])
{
#autoreleasepool {
//int retVal = UIApplicationMain(argc, argv, nil, nil);
int retVal = UIApplicationMain(argc, argv, nil, NSStringFromClass([newIsiKotaAppDelegate class]));
return retVal;
}
}
I manage to spot that the last code executed is this:
self.lblTimeLeft.attributedText = arString;
I provided additional code to test things out
NSAttributedString * arString = [self asSchedule:arTimes];
self.lblTimeLeft.attributedText = arString;
PO1(#"Hello World");
while(false);// Error happen after this code is executed
}
The code is part of the routine that provides UITableViewCell to display. So error happen after
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSUInteger row = indexPath.row;
NSDictionary * rowDictionary = _marManagedObjectArray [row];
BGCinemaScheduleCell * BCS = [[BGCinemaScheduleCell alloc]init];
BCS.dicCinemaDictionary =rowDictionary;
return BCS; //This is where the error happen
}
It seems that the NSAttributedString works fine till it's actually displayed or something.
The error seems to happen on
TAttributes::TAttributes(__CFDictionary const *)
The content of asSchedule is usual
-(NSAttributedString *) asSchedule:(NSArray *) arTimes
{
NSMutableArray * timeBefore = [NSMutableArray array];
NSMutableArray * timeAfter = [NSMutableArray array];
for (NSString * strTime in arTimes) {
NSDate * date = [NSDate dtWithCurrentDateAndProvidedTime: strTime];
NSTimeInterval dblInterval =[date timeIntervalSinceNow];
if (dblInterval>0)
{
[timeAfter addObject:strTime];
}
else{
[timeBefore addObject:strTime];
}
}
NSString * strTimeBefore = [timeBefore componentsJoinedByString:#" "];
NSString * strTimeAfter = [timeAfter componentsJoinedByString:#" "];
NSString *yourString = [NSString stringWithFormat:#"%# %#", strTimeBefore, strTimeAfter];
// start at the end of strTimeBefore and go the length of strTimeAfter
NSRange boldedRange = NSMakeRange([strTimeBefore length] + 1, [strTimeAfter length]);
NSString *boldFontName = [[UIFont boldSystemFontOfSize:12] fontName];
NSMutableAttributedString *attrString = [[NSMutableAttributedString alloc] initWithString:yourString];
[attrString addAttribute:NSFontAttributeName value:boldFontName range:boldedRange];
PO1(NSStringFromRange(boldedRange));
PO1(#(attrString.length));
return attrString;
}
Update:
I changed self.lblTimeLeft.attributedText = arString; to self.lblTimeLeft.attributedText = arString.copy; to no avail.
I wonder if this could be the problem:
[attrString addAttribute:NSFontAttributeName value:boldFontName range:boldedRange];
I think the original sample use KCFont something instead of NSFontAttributeName
You were almost there:
I wonder if this could be the problem: [attrString addAttribute:NSFontAttributeName value:boldFontName range:boldedRange];
Your code says:
NSString *boldFontName = [[UIFont boldSystemFontOfSize:12] fontName];
...
[attrString addAttribute:NSFontAttributeName value:boldFontName range:boldedRange];
It should say:
UIFont *boldFont = [UIFont boldSystemFontOfSize:12];
...
[attrString addAttribute:NSFontAttributeName value:boldFont range:boldedRange];
According to Table 1 of the docs (link below) and my own app code, you should be passing an NSFont not a font name.
https://developer.apple.com/library/ios/documentation/cocoa/Conceptual/AttributedStrings/Articles/standardAttributes.html#//apple_ref/doc/uid/TP40004903-SW2
Can't tell from the code whether your project uses ARC or not, but it looks like your asSchedule method returns a string with a refcount of 0. It's up to you to retain a reference to that string, either old-school using the retain keyword (probably a bad idea) or by assigning it to a property declared with the strong keyword (or retain, if pre-ARC).
The best tool for debugging this stuff is Instruments, using the Zombies inspection. If I am right that you are trying to use the string after its refcount hits 0 and the memory has been released, you'll see the history of refcount increments and decrements pretty clearly.
Try alloc and initing the Attributedstring and then assign it to the self.lblTimeLeft.attributedText