Issues regarding NSTextStorage
Issues regarding NSTextStorage
- Subject: Issues regarding NSTextStorage
- From: Vadim Lozko <email@hidden>
- Date: Fri, 29 Apr 2011 07:49:07 -0400
- Acceptlanguage: en-US
- Thread-topic: Issues regarding NSTextStorage
I've originally posted this on the dev forums but after a few days it's
only gotten 8 views and no replies. I'm hoping for a bit more luck here.
Here's the original post:
We use a subclass of NSTextStorage that enables us to do live word and
page count. The final product, however, must be written out in MS Word
format. Currently there are two versions (which we plan to merge into one
eventually) in which version a doesn't exhibit the problem and version b
does. We could end up just being lucky as to why version a doesn't as the
failure rate is about 6%. The problem is that whenever we export out the
file in a Doc format, it will on occasion not reopen as either an
NSAttributedString or even in Word. When attempting to recover the file in
Word 2008, there is some extra stuff added to the end of the document that
appears to relate to formatting. Specifically, we get this:
Normal
Normal
Default Paragraph Font
Default Paragraph Font
Times New Roman
Times New Roman
Symbol
Symbol
Helvetica
Helvetica
Root Entry
1Table
1Table
WordDocument
WordDocument
SummaryInformation
SummaryInformation
DocumentSummaryInformation
DocumentSummaryInformation
I'm assuming this is the font/formatting table similar to how an RTF
document is formatted.
The major difference between version a and b is that version b has the
ability to insert a page break. The code to do it is:
[[self firstTextView] insertContainerBreak:nil];
I've tried run various test to see if container breaks are the cause of
the corruption but I haven't been able to duplicate it. This is the header
and implementation of our subclassed text storage:
@interface SESTextStorage : NSTextStorage
{
NSMutableAttributedString *text;
NSUInteger wordCount;
NSCharacterSet* lettersAndNumbers;
}
- (id)initWithAttributedString:(NSAttributedString *)aString
wordCount:(unsigned)wc;
- (NSData *)wordDocumentFromText;
@property (readonly) NSUInteger wordCount;
@end
---------------------------------------
#import "SESConstants.h"
#import "SESTextStorage.h"
@implementation SESTextStorage
- (NSUInteger)wordCountForRange:(NSRange)range
{
NSUInteger wc = 0;
int index = range.location;
while (index < NSMaxRange(range))
{
int newIndex = [self nextWordFromIndex:index forward:YES];
NSString *word = [[self string]
substringWithRange:NSMakeRange(index, newIndex-index)];
if ([word rangeOfCharacterFromSet:lettersAndNumbers].location !=
NSNotFound)
{
wc++;
}
index = newIndex;
}
return wc;
}
- (NSRange)wordRangeForCharRange:(NSRange)charRange
{
NSRange wordRange;
wordRange.location = [self nextWordFromIndex:charRange.location
forward:NO];
wordRange.length = [self nextWordFromIndex:NSMaxRange(charRange)
forward:YES] - wordRange.location;
return wordRange;
}
- (NSUInteger)wordCount
{
return wordCount;
}
#pragma mark -
#pragma mark NSTextStorage Overrides
- (id)init
{
if (nil != (self = [super init]))
{
text = [[NSMutableAttributedString alloc] init];
lettersAndNumbers = [[NSCharacterSet
alphanumericCharacterSet] retain];
wordCount = 0;
}
return self;
}
- (id)initWithAttributedString:(NSAttributedString *)aString
{
if (nil != (self = [super init]))
{
text = [aString mutableCopy];
wordCount = [self wordCountForRange:NSMakeRange(0,[text
length])];
}
return self;
}
- (id)initWithAttributedString:(NSAttributedString *)aString
wordCount:(unsigned)wc
{
if (nil != (self = [super init]))
{
text = [aString mutableCopy];
wordCount = wc;
}
return self;
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[lettersAndNumbers release];
[text release];
[super dealloc];
}
- (NSString *)string
{
return [text string];
}
- (NSDictionary *)attributesAtIndex:(NSUInteger)index
effectiveRange:(NSRangePointer)aRange
{
return [text attributesAtIndex:index effectiveRange:aRange];
}
- (void)replaceCharactersInRange:(NSRange)aRange withString:(NSString
*)aString
{
int strlen = [aString length];
NSRange wcRange = [self wordRangeForCharRange:aRange];
wordCount -= [self wordCountForRange:wcRange];
NSRange changedRange = NSMakeRange(wcRange.location, (wcRange.length
- aRange.length) + strlen);
[text replaceCharactersInRange:aRange withString:aString];
int lengthChange = strlen - aRange.length;
[self edited:NSTextStorageEditedCharacters range:aRange
changeInLength:lengthChange];
wordCount += [self wordCountForRange:changedRange];
[[NSNotificationCenter defaultCenter]
postNotificationName:SESTextStorageStatisticsDidChangeNotification
object:self];
}
- (void)setAttributes:(NSDictionary *)attributes range:(NSRange)aRange
{
[text setAttributes:attributes range:aRange];
[self edited:NSTextStorageEditedAttributes range:aRange
changeInLength:0];
}
- (void)addAttribute:(NSString *)name value:(id)value range:(NSRange)aRange
{
[text addAttribute:name value:value range:aRange];
[self edited:NSTextStorageEditedAttributes range:aRange
changeInLength:0];
}
- (NSData *)wordDocumentFromText
{
NSMutableDictionary *dict = [NSMutableDictionary
dictionaryWithObjectsAndKeys:
[NSValue valueWithSize:NSMakeSize(8.5,
11.0)], @"PaperSize",
[NSNumber numberWithFloat:1.0],
@"LeftMargin",
[NSNumber numberWithFloat:1.0],
@"RightMargin",
[NSNumber numberWithFloat:1.0],
@"BottomMargin",
[NSNumber numberWithFloat:1.0],
@"TopMargin",
nil];
NSData *docData = [self docFormatFromRange:NSMakeRange(0, [self length])
documentAttributes:dict];
NSDictionary* options = [NSDictionary
dictionaryWithObject:NSDocFormatTextDocumentType
forKey:NSDocumentTypeDocumentOption];
NSError* error = nil;
NSAttributedString *string = [[NSAttributedString alloc]
initWithData:docData
options:options
documentAttributes:nil
error:&error];
if (nil == string)
{
SSILog(kLogErrorLevel, @"Error in recreating string from Doc format
string: %@", [error localizedDescription]);
}
else if (abs([[self string] length] - [[string string] length]) > 2)
{
SSILog (kLogWarningLevel, @"Size mismatch in rereading save
data.\nCurrent string length: %i\nSaved string:%i",
[[self string] length], [[string string] length]);
}
else
{
SSILog (kLogInfoLevel, @"Document length verified for save request.");
}
[string release];
return docData;
}
@dynamic wordCount;
@end
The main save method is "-[SESTextStorage wordDocumentFromText]". The
issue was discovered here. The NSData gets created from the text storage's
content. However, upon regenerating the string back from the data for the
purpose of a sanity check, the string comes back as nil. The error I get
is "The file couldn¹t be opened because it isn¹t in the correct format."
So, I guess my question is, what is causing my Word files to be corrupted?
My suspicion is how I insert a page break with my second guess being
something to do with the word/page count implementation.
Thanks for any help
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden