Trying to read in an RTF file in Objective-C - objective-c

I have an RTF file that I am reading in using a command line application in Objective-C. I'm using Dave DeLong's code from this question: How to read data from NSFileHandle line by line?
My problem is that my output is coming out like this:
2014-06-21 20:03:45.578 AjrumTest[5663:303] {\rtf1\ansi\ansicpg1252\cocoartf1265\cocoasubrtf200
2014-06-21 20:03:45.579 AjrumTest[5663:303] {\fonttbl\f0\fnil\fcharset0 LucidaGrande;\f1\fnil\fcharset178 AlBayan;\f2\froman\fcharset0 TimesNewRomanPSMT;
2014-06-21 20:03:45.580 AjrumTest[5663:303] \f3\fnil\fcharset178 GeezaPro;}
2014-06-21 20:03:45.580 AjrumTest[5663:303] {\colortbl;\red255\green255\blue255;}
2014-06-21 20:03:45.581 AjrumTest[5663:303] \margl1440\margr1440\vieww10800\viewh8400\viewkind0
2014-06-21 20:03:45.581 AjrumTest[5663:303] \deftab720
2014-06-21 20:03:45.581 AjrumTest[5663:303] \pard\pardeftab720
2014-06-21 20:03:45.582 AjrumTest[5663:303]
2014-06-21 20:03:45.582 AjrumTest[5663:303] \f0\fs46 \cf0 1
2014-06-21 20:03:45.582 AjrumTest[5663:303] \f1 - \'de\'f3\'dc\'c7\'e1\'f3 \'c7\'c8\'fa\'dc\'e4\'f5 \'c2\'c8\'f3\'f8 \'e6\'f3\'c7\'d3\'fa\'e3\'f5\'dc\'e5\'f5 \'e3\'f5\'cd\'f3\'e3\'f3\'f8\'dc\'cf\'f5
...
I realize that because the document I am reading in is an RTF file, that I need to attach the necessary attributes to it. I pass in my file from the main method like this:
NSString *pathToMyFile = [[NSBundle mainBundle] pathForResource:#"MyRTFDocument" ofType:#"rtf"];
DDFileReader * reader = [[DDFileReader alloc] initWithFilePath:pathToMyFile];
[reader enumerateLinesUsingBlock:^(NSString *line, BOOL *stop) {
NSLog(#"%#", line);
}];
Here is how the document is then parsed:
- (NSString *) readLine {
if (currentOffset >= totalFileLength) {
return nil;
}
NSData *newLineData = [lineDelimiter dataUsingEncoding:NSUTF8StringEncoding];
[fileHandle seekToFileOffset:currentOffset];
NSMutableData * currentData = [[NSMutableData alloc] init];
BOOL shouldReadMore = YES;
#autoreleasepool {
while (shouldReadMore) {
if (currentOffset >= totalFileLength) {
break;
}
NSData *chunk = [fileHandle readDataOfLength:chunkSize];
NSRange newLineRange = [chunk rangeOfData_dd:newLineData];
if (newLineRange.location != NSNotFound) {
//include the length so we can include the delimiter in the string
chunk = [chunk subdataWithRange:NSMakeRange(0, newLineRange.location+[newLineData length])];
shouldReadMore = NO;
}
[currentData appendData:chunk];
currentOffset += [chunk length];
}
}
NSDictionary *attrs = #{NSDocumentTypeDocumentAttribute: NSRTFTextDocumentType, NSWritingDirectionAttributeName:#[#(NSWritingDirectionRightToLeft | NSTextWritingDirectionOverride)]};
NSAttributedString *attrString = [[NSAttributedString alloc] initWithData:currentData options:attrs documentAttributes:nil error:nil];
//NSLog(#"What does this give me? %#", [attrString string]);
//The above line outputs (null) for [attrString string]
NSString *line = [[NSString alloc] initWithData:currentData encoding:NSUTF8StringEncoding];
return line;
}
- (NSString *) readTrimmedLine {
return [[self readLine] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}
#if NS_BLOCKS_AVAILABLE
- (void) enumerateLinesUsingBlock:(void(^)(NSString*, BOOL*))block {
NSString *line = nil;
BOOL stop = NO;
while (stop == NO && (line = [self readLine])) {
block(line, &stop);
}
}
#endif
When I attach the correct document attributes to the NSData object before creating an NSAttributedString, I get an object that is null:
NSDictionary *attrs = #{NSDocumentTypeDocumentAttribute: NSRTFTextDocumentType, NSWritingDirectionAttributeName:#[#(NSWritingDirectionRightToLeft | NSTextWritingDirectionOverride)]};
NSAttributedString *attrString = [[NSAttributedString alloc] initWithData:currentData options:attrs documentAttributes:nil error:nil];
NSLog(#"%#", [attrString string]);
In another iOS application, I have the following code which works exactly as I want:
NSString *path = [[NSBundle mainBundle] pathForResource:#"AjrumiyyahPoemRawTextRTF" ofType:#"rtf"];
NSData *testData = [NSData dataWithContentsOfFile:path];
NSDictionary *attrs = #{NSDocumentTypeDocumentAttribute: NSRTFTextDocumentType, NSWritingDirectionAttributeName:#[#(NSWritingDirectionRightToLeft | NSTextWritingDirectionOverride)]};
NSAttributedString *attrString = [[NSAttributedString alloc] initWithData:testData options:attrs documentAttributes:nil error:nil];
NSLog(#"The text of the document is: %#", [attrString string]);
What it is that I need to do to the command line application to attach the document attributes to the NSAttributedString object correctly so that the output is correct?

I don't have an immediate answer, but with regards to this line of code:
NSAttributedString *attrString = [[NSAttributedString alloc] initWithData:currentData options:attrs documentAttributes:nil error:nil];
You should use the error variable to figure out why the result is null / nil. So instead write something like the following:
NSError *error = nil;
NSAttributedString *attrString = [[NSAttributedString alloc] initWithData:currentData options:attrs documentAttributes:nil error:&error];
If (attrString == nil) // parsing failed, so read out error
{
NSLog(#"%#", error);
}
Perhaps this will help you figure out what goes wrong.

Related

Create ICS with objective C

I am writing an app for students at my university. At this point I want to export the lessons in the schedule as an ics-file. I have wrote something that works with csv-files, but now I want the same for ics.
The problem is that iCal at my Mac doesn't want the in-app-created ics-files from this code:
-(NSURL*)getFileUrl
{
NSString *docsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *filePath = [docsPath stringByAppendingPathComponent:[NSString stringWithFormat:#"Stundenplan-%#.ics", _MatrNr]];
NSURL *fileUrl = [NSURL fileURLWithPath:filePath];
NSError *error = nil;
[[self getICSData] writeToURL:fileUrl atomically:YES];
if (error) {
NSLog(#"Error while writing to File: %#", [error localizedDescription]);
}
return fileUrl;
}
-(NSData*)getICSData
{
NSMutableString *erg = [[NSMutableString alloc] init];
NSDate *aktDatum = [NSDate date];
[erg appendString:[NSString stringWithFormat:#"BEGIN:VCALENDAR\nVERSION:2.0\nPRODID:-//www.htw-dresden.de//iOS//DE\nMETHOD:PUBLISH\n"]];
for (Stunde *this in _daten) {
NSString *titel = [this.titel stringByReplacingOccurrencesOfString:#"," withString:#"\\, "];
NSString *dozent = [this.dozent stringByReplacingOccurrencesOfString:#"," withString:#"\\, "];
NSString *uuid = [[NSUUID UUID] UUIDString];
[erg appendString:[NSString stringWithFormat:#"BEGIN:VEVENT\nUID:%#\n", uuid]];
[erg appendString:[NSString stringWithFormat:#"DTSTART:%#T%#Z\n",[self nurTagFromDate:this.anfang], [self nurUhrzeigFromDate:this.anfang]]];
[erg appendString:[NSString stringWithFormat:#"DTEND:%#T%#Z\n",[self nurTagFromDate:this.ende], [self nurUhrzeigFromDate:this.ende]]];
[erg appendString:[NSString stringWithFormat:#"LAST-MODIFIED:%#T%#Z\nSEQUENCE:0\nSTATUS:CONFIRMED\n", [self nurTagFromDate:aktDatum], [self nurUhrzeigFromDate:aktDatum]]];
[erg appendString:[NSString stringWithFormat:#"SUMMARY:%#\nDESCRIPTION:%#\nLOCATION:%#\nEND:VEVENT\n", titel, dozent, this.raum]];
}
[erg appendString:#"END:VCALENDER"];
NSData *ret = [erg dataUsingEncoding:NSUTF8StringEncoding];
return ret;
}
In the getFileUrl I want to return a URL to the file created in there. This function calls the getICSData function that goes through my array (_daten) and creates for every Stunde object this ics-"code".
For help I have these NSDate formatting functions:
-(NSString*)nurTagFromDate:(NSDate*)date
{
NSDateFormatter *nurTag = [[NSDateFormatter alloc] init];
[nurTag setDateFormat:#"yyyyMMdd"];
return [nurTag stringFromDate:date];
}
-(NSString*)nurUhrzeigFromDate:(NSDate*)date
{
NSDateFormatter *nurTag = [[NSDateFormatter alloc] init];
[nurTag setDateFormat:#"HHmmss"];
return [nurTag stringFromDate:date];
}
As output I get something like this:
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//www.htw-dresden.de//iOS//DE
METHOD:PUBLISH
BEGIN:VEVENT
UID:CCCAC9B3-E056-47E3-A63B-F2FE2C3BA454
DTSTART:20140318T111000Z
DTEND:20140318T124000Z
LAST-MODIFIED:20140429T182723Z
SEQUENCE:0
STATUS:CONFIRMED
SUMMARY:Internet-Technologien I
DESCRIPTION:Vogt\, J.
LOCATION:Z 254
END:VEVENT
.
.
.
END:VCALENDER
But the calendar app at my Mac don't want to open the file...
It would be great if some of you will have an Idea :)
Replace this line:
[erg appendString:#"END:VCALENDER"];
With this:
[erg appendString:#"END:VCALENDAR"];
Notice the typo in VCALENDAR.
You may find this iCal file validator useful.

How to get data to write to a text file?

Here is the method that I'm using for a console output. How can I output to a text file?
#implementation GetMoves
- (id)initWithDevice:(Device *)device{
if(self = [super init]){
_device = device;
}
return self;
}
- (void)Render{
[super ClearConsole];
printf("MOVES INFO\n");
printf("==================================\n");
NSArray* data = [_device GetData:NULL];
NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd HH:mm:ss"];
if(data != nil){
for(int i = 0; i < data.count; i++){
DataPoint* current = [data objectAtIndex:i];
NSMutableString* output = [[NSMutableString alloc] init];
[output appendFormat:#"%d",(i+1)];
[output appendString:#" - "];
[output appendString:[dateFormatter stringFromDate:current.RecordedAt]];
[output appendString:#" - "];
[output appendFormat:#"%d",current.StepCount];
printf("%s\n", [output UTF8String]);
}
}
else
printf("No new data found on device.\n");
printf("\n");
printf("==================================\n");
printf("\n");
printf("Press ENTER to continue.");
fgetc(stdin);
}
#end
You can simply write as :
NSString *path = [#"~" stringByExpandingTildeInPath] ;
//change your path here
path=[path stringByAppendingString:#"/Documents/*REPORTS/"];
//make a file name to write the data to using the documents directory:
NSString *fileName = [NSString stringWithFormat:#"%#/TWCodeFile.txt",path];
//create content - four lines of text
NSString *content = #"The content of file, can be more by appending string.";
//save content to the documents directory
[content writeToFile:fileName
atomically:NO
encoding:NSStringEncodingConversionAllowLossy
error:nil];

objective c - convert mpmediaitem to ogg vorbis

i found (customizing a method i found) a way to convert a MpMediaItem and to obtain a mp3 file. Probably it's not the best way but it's working.
Is there a way to obtain an *.ogg file instead of *.mp3 ? What would be the proper approach?
This is the method i use to get the *.mp3 file:
-(void)exportMP3:(NSURL*)url toFileUrl:(NSString*)fileURL
{
AVURLAsset *asset=[[AVURLAsset alloc] initWithURL:url options:nil];
AVAssetReader *reader=[[AVAssetReader alloc] initWithAsset:asset error:nil];
NSMutableArray *myOutputs =[[NSMutableArray alloc] init];
for(id track in [asset tracks])
{
AVAssetReaderTrackOutput *output=[AVAssetReaderTrackOutput assetReaderTrackOutputWithTrack:track outputSettings:nil];
[myOutputs addObject:output];
[reader addOutput:output];
}
[reader startReading];
NSFileHandle *fileHandle ;
NSFileManager *fm=[NSFileManager defaultManager];
if(![fm fileExistsAtPath:fileURL])
{
[fm createFileAtPath:fileURL contents:[[NSData alloc] init] attributes:nil];
}else{
NSURL *url = [NSURL URLWithString:fileURL];
[fm removeItemAtURL:url error:nil];
[fm createFileAtPath:fileURL contents:[[NSData alloc] init] attributes:nil];
}
fileHandle=[NSFileHandle fileHandleForWritingAtPath:fileURL];
[fileHandle seekToEndOfFile];
AVAssetReaderOutput *output=[myOutputs objectAtIndex:0];
int totalBuff=0;
int test = 1;
while(test == 1)
{
CMSampleBufferRef ref=[output copyNextSampleBuffer];
if(ref==NULL)
test = 0;
if(ref==NULL)
break;
//copy data to file
//read next one
AudioBufferList audioBufferList;
NSMutableData *data;
CMBlockBufferRef blockBuffer;
CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(ref, NULL, &audioBufferList, sizeof(audioBufferList), NULL, NULL, 0, &blockBuffer);
for( int y=0; y<audioBufferList.mNumberBuffers; y++ )
{
AudioBuffer audioBuffer = audioBufferList.mBuffers[y];
void *frame = audioBuffer.mData;
data = [[NSMutableData alloc] initWithBytes:frame length:audioBuffer.mDataByteSize];
}
totalBuff++;
NSLog(#"\n%d\n",totalBuff);
int time = [self.mediaPlayer durationOfCurrentItem];
if (totalBuff * 2 <= time + 1)
[fileHandle writeData:data];
}
[fileHandle closeFile];
}
You can use libvorbis to encode PCM data to Vorbis.

Fix unicode characters in NSString

I am getting a string response from the Google Directions API that contains characters that are supposed to represent a different-language character. Similiar to Ƨ³, similiar to these type of characters. I think the characters are portugese, but anyways my string contains like this:
\U00e3o
(I am not sure if those are zeroes or 'O's)
I am not sure what the technical term for these characters are, but how can I fix them in my string so they print properly.
Thank you
UPDATE:
I have updated my question title with the correct term 'unicode'.
I have checked a few questions:
NSString Unicode display
Detect Unicode characters in NSString on iPhone
iOS HTML Unicode to NSString?
And a few others. I have followed the answer, but the unicode characters are not fixed.
UPDATE:
Here is my code to get the response from GDirection.
Forming the request and getting a response:
AFHTTPClient *_httpClient = [AFHTTPClient clientWithBaseURL:[NSURL URLWithString:#"http://maps.googleapis.com/"]];
[_httpClient registerHTTPOperationClass: [AFJSONRequestOperation class]];
[_httpClient setDefaultHeader:#"Accept" value:#"application/json"];
NSMutableDictionary *parameters = [[NSMutableDictionary alloc] init];
[parameters setObject:[NSString stringWithFormat:#"%f,%f", location.coordinate.latitude, location.coordinate.longitude] forKey:#"origin"];
[parameters setObject:[NSString stringWithFormat:#"%f,%f", location2.coordinate.latitude, location2.coordinate.longitude] forKey:#"destination"];
[parameters setObject:#"false" forKey:#"sensor"];
[parameters setObject:#"driving" forKey:#"mode"];
[parameters setObject:#"metric" forKey: #"units"];
NSMutableURLRequest *request = [_httpClient requestWithMethod:#"GET" path: #"maps/api/directions/json" parameters:parameters];
request.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
AFHTTPRequestOperation *operation = [_httpClient HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSInteger statusCode = operation.response.statusCode;
if (statusCode == 200) {
[self parseResponse:responseObject];
} else {
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) { }];
[_httpClient enqueueHTTPRequestOperation:operation];
}
Retrieving information from response object:
- (void)parseResponse:(NSDictionary *)response {
NSString *status = [response objectForKey: #"status"];
if (![status isEqualToString: #"OK"]) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error" message:[NSString stringWithFormat: #"Google Directions Response Status: %#", status] delegate:self cancelButtonTitle:#"Dismiss" otherButtonTitles:nil, nil];
[alert show];
}
else {
NSArray *routes = [response objectForKey:#"routes"];
NSDictionary *routePath = [routes lastObject];
if (routePath) {
NSString *overviewPolyline = [[routePath objectForKey: #"overview_polyline"] objectForKey:#"points"];
legs = [routePath valueForKey: #"legs"];
if (legs) {
/* DIRECTION SET ================================================================================================================================
*/
directionOverview = [[NSMutableDictionary alloc] init];
NSString *legsDis = [NSString stringWithFormat: #"%#", [[legs valueForKey: #"distance"] valueForKey: #"text"]];
NSString *kmDistance = [self cutStringToPreference: legsDis];
if (kmDistance) {
[directionOverview setObject:kmDistance forKey: #"distance"];
milesLabel.text = kmDistance;
milesLabel.font = [UIFont fontWithName:#"interstate" size: 20.0];
}
NSString *durationText = [NSString stringWithFormat: #"%#", [[legs valueForKey: #"duration"] valueForKey: #"text"]];
durationText = [self cutStringToPreference: durationText];
if (durationText) {
[directionOverview setObject:durationText forKey: #"duration"];
}
NSString *startAddress = [NSString stringWithFormat: #"%#", [legs valueForKey: #"start_address"]];
startAddress = [self cutStringToPreference: startAddress];
NSString *endAddress = [NSString stringWithFormat: #"%#", [legs valueForKey: #"end_address"]];
endAddress = [self cutStringToPreference: endAddress];
[directionOverview setObject:startAddress forKey: #"origin"];
[directionOverview setObject:endAddress forKey: #"destination"];
NSArray *steps = [legs valueForKey: #"steps"];
if (steps) {
instructionArray = [[NSMutableArray alloc] init];
durationArray = [[NSMutableArray alloc] init];
distanceArray = [[NSMutableArray alloc] init];
int number = [[[steps lastObject] valueForKey: #"html_instructions"] count];
for (int i = 1; i <= number; ++i) {
NSString *instruction = [[[steps lastObject] valueForKey: #"html_instructions"] objectAtIndex: i-1];
instruction = [self cutStringToPreference: instruction];
instruction = [self flattenHTML: instruction];
instruction = [self stringByDecodingHTMLEntitiesInString: instruction];
[instructionArray addObject: instruction];
NSString *distance = [[[[steps lastObject] valueForKey: #"distance"] objectAtIndex: i-1] valueForKey: #"text"];
[distanceArray addObject: distance];
NSString *duration = [[[[steps lastObject] valueForKey: #"duration"] objectAtIndex: i-1] valueForKey: #"text"];
[durationArray addObject: duration];
}
}
}
_path = [self decodePolyLine:overviewPolyline];
NSInteger numberOfSteps = _path.count;
CLLocationCoordinate2D coordinates[numberOfSteps];
for (NSInteger index = 0; index < numberOfSteps; index++) {
CLLocation *location = [_path objectAtIndex:index];
CLLocationCoordinate2D coordinate = location.coordinate;
coordinates[index] = coordinate;
}
polyLine = [MKPolyline polylineWithCoordinates:coordinates count:numberOfSteps];
[self.mapView addOverlay:polyLine];
}
}
}
Displaying the text in a label:
NSString *overviewAddressText = [NSString stringWithFormat: #"%# to %#", [directionOverview objectForKey: #"origin"], [directionOverview objectForKey: #"destination"]];
overviewAddress.text = overviewAddressText;
UPDATE:
Image of label
So as you can see, in the label, the text contains this kind of substring: S/U00e3o, which is a word that has an unsupported character. How can I fix that so that unicode turns into this: São

Parse JSON in Objective-C with SBJSON

I just want to parse this JSON string in Objective-C using the SBJSON framework, and retrieve the three units of data:
{"x":"197","y":"191","text":"this is a string"}
How can this be done?
NSString * jsonString = #"{\"x\":\"197\",\"y\":\"191\",\"text\":\"this is a string\"}";
SBJSON *jsonParser = [[SBJSON alloc] init];
NSDictionary * dictionary = [jsonParser objectWithString:jsonString];
NSLog(#"x is %#",[dictionary objectForKey:#"x"]);
[jsonParser release];
Here's an example:
NSString *jsonText = #"...";
SBJsonParser *parser = [[SBJsonParser alloc] init];
NSDictionary *dict = [parser objectWithString:jsonText];
for (NSString *key in [#"x y text" componentsSeparatedByString:#" "]) {
NSLog(#"%# => %#", key, [dict objectForKey]);
}
Here's something similar for SBJson4Parser:
id parser = [SBJson4Parser parserWithBlock:^(id v, BOOL *stop) {
for (NSString *key in [#"x y text" componentsSeparatedByString:#" "]) {
NSLog(#"%# => %#", key, [v objectForKey]);
}
}
allowMultiRoot:NO
unwrapRootArray:NO
errorHandler:^(NSError *err) {
// handle error here
}];
NSString *jsonText = #"...";
[parser parse: [jsonText UTF8String]];