diff --git a/OpenChange/RTFHandler.h b/OpenChange/RTFHandler.h index b0ea0b684..ec776a8d3 100644 --- a/OpenChange/RTFHandler.h +++ b/OpenChange/RTFHandler.h @@ -28,6 +28,8 @@ // // // +@class RTFFontTable; + @interface RTFHandler : NSObject { NSMapTable *_charsets; @@ -41,6 +43,11 @@ - (id) initWithData: (NSData *) theData; - (NSMutableData *) parse; + +- (RTFFontTable *) parseFontTable; +- (void) mangleInternalStateWithBytesPtr: (const char*) newBytes + andCurrentPos: (int) newCurrentPos; + @end // @@ -84,6 +91,7 @@ unsigned int index; } +- (NSString *) description; @end // @@ -97,8 +105,8 @@ - (void) addFontInfo: (RTFFontInfo *) theFontInfo atIndex: (unsigned int ) theIndex; - - (RTFFontInfo *) fontInfoAtIndex: (unsigned int ) theIndex; +- (NSString *) description; @end diff --git a/OpenChange/RTFHandler.m b/OpenChange/RTFHandler.m index b18754e51..d4f775b5d 100644 --- a/OpenChange/RTFHandler.m +++ b/OpenChange/RTFHandler.m @@ -21,6 +21,7 @@ #include "RTFHandler.h" #include +#include // // Useful macros @@ -352,6 +353,7 @@ const unsigned short ansicpg874[256] = { RTFFontInfo *fontInfo; description = [NSMutableString stringWithFormat: @"Number of fonts: %u\n", [fontInfos count]]; + enumerator = [fontInfos objectEnumerator]; while ((fontInfo = [enumerator nextObject])) { @@ -563,6 +565,9 @@ static void _init_fontCws_table() [super dealloc]; } +/* + Returns pointer to the control word and in len pointer its length including numeric argument +*/ - (const char *) parseControlWord: (unsigned int *) len { const char *start, *end; @@ -1457,4 +1462,12 @@ inline static void parseUl(RTFHandler *self, BOOL hasArg, int arg, RTFFormatting return [_html autorelease]; } +/* This method is for ease of testing and should not be used in normal operations */ +- (void) mangleInternalStateWithBytesPtr: (const char*) newBytes + andCurrentPos: (int) newCurrentPos +{ + _bytes = newBytes; + _current_pos = newCurrentPos; +} + @end diff --git a/Tests/Unit/TestRTFHandler.m b/Tests/Unit/TestRTFHandler.m index e4b72f8dd..1158a8c0d 100644 --- a/Tests/Unit/TestRTFHandler.m +++ b/Tests/Unit/TestRTFHandler.m @@ -23,9 +23,14 @@ /* This file is encoded in utf-8. */ #import "RTFHandler.h" -#import #import "SOGoTest.h" +#import +#import + +#include + + @interface TestRTFHandler : SOGoTest @end @@ -35,20 +40,32 @@ - (NSString *) rtf2html: (NSData *) rtf { NSString *html; - if (!rtf) return @"nil"; + if (!rtf) + return nil; + RTFHandler *handler = [[RTFHandler alloc] initWithData: rtf]; NSMutableData *data2 = [handler parse]; + if (data2 == nil) + { + NSString *error = [NSString stringWithFormat: @"Couldn't parse RTF data:\n %s", + (char *)[rtf bytes]]; + testWithMessage(NO, error); + } + html = [[NSString alloc] initWithData: data2 encoding: NSUTF8StringEncoding]; - if (html == nil) { - html = [[NSString alloc] initWithData: data2 encoding: NSASCIIStringEncoding]; - } - if (html == nil) { - html = [[NSString alloc] initWithData: data2 encoding: NSISOLatin1StringEncoding]; - } - if (html == nil) { - NSString *error = [NSString stringWithFormat: @"Couldn't convert parsed data"]; - testWithMessage(false, error); - } + if (html == nil) + { + html = [[NSString alloc] initWithData: data2 encoding: NSASCIIStringEncoding]; + } + if (html == nil) + { + html = [[NSString alloc] initWithData: data2 encoding: NSISOLatin1StringEncoding]; + } + if (html == nil) + { + NSString *error = [NSString stringWithFormat: @"Couldn't convert parsed data"]; + testWithMessage(NO, error); + } return html; } @@ -85,10 +102,50 @@ in = [self dataWithContentsOfFixture: file]; out = [self rtf2html: in]; error = [NSString stringWithFormat: - @"Html from rtf result is not what we expected.\nActual:\n%@\n Expected:\n%@\n", out, expected]; + @"Html from rtf result is not what we expected.\n>> Actual:\n%@\n>> Expected:\n%@\n", out, expected]; testWithMessage([out isEqualToString: expected], error); } +- (void) checkFonTableParsingOfRTFFile: (NSString*) file + againstExpectedTable: (NSString*) expected +{ + NSData *in = nil; + char *in_bytes; + char *table_pointer; + int newCurrentPos; + RTFHandler *handler; + RTFFontTable *out_table; + NSString *out_description, *error = nil; + + in = [self dataWithContentsOfFixture: file]; + in_bytes = (char *) [in bytes]; + table_pointer = strstr(in_bytes, "{\\fonttbl"); + if (table_pointer == NULL) + { + [NSException raise: @"NSInvalidArgumentException" + format: @"No font table in RTF file"]; + } + newCurrentPos = table_pointer - in_bytes; + + handler = [[RTFHandler alloc] initWithData: in]; + + [handler mangleInternalStateWithBytesPtr: table_pointer + andCurrentPos: newCurrentPos]; + out_table = [handler parseFontTable]; + out_description = [out_table description]; + if ([out_description isEqualToString: expected]) + { + testWithMessage(YES, @"no error"); + } + else + { + error = [NSString stringWithFormat: + @"Font table is not what we expected.\n>> Actual:\n%@-----\n>> Expected:\n%@-----\n", out_description, expected]; + testWithMessage(NO, error); + } + +} + - (void) test_zentyal_crash_2058 { @@ -102,7 +159,7 @@ NSString *out = nil, *error = nil, *expected = nil; in = [self dataWithContentsOfZentyalCrash: 2089]; - expected = @"Lorem Ipsum"; + expected =@"Lorem Ipsum
"; out = [self rtf2html: in]; error = [NSString stringWithFormat: @"Html from rtf result `%@` is not what we expected", out]; @@ -129,6 +186,100 @@ [self checkDoesNotCrash: 7067]; } + +- (void) test_mini_russian_font_table +{ + NSString *file =@"mini_russian.rtf"; + NSMutableString *expected = [NSMutableString stringWithFormat: @"Number of fonts: 84\n"]; + [expected appendString: @"0 name=Times New Roman family=roman charset=0 pitch=2\n"]; + [expected appendString: @"31500 name=Times New Roman family=roman charset=0 pitch=2\n"]; + [expected appendString: @"31501 name=Times New Roman family=roman charset=0 pitch=2\n"]; + [expected appendString: @"31502 name=Cambria family=roman charset=0 pitch=2\n"]; + [expected appendString: @"37 name=Calibri family=swiss charset=0 pitch=2\n"]; + [expected appendString: @"31503 name=Times New Roman family=roman charset=0 pitch=2\n"]; + [expected appendString: @"39 name=Times New Roman CE family=roman charset=238 pitch=2\n"]; + [expected appendString: @"31504 name=Times New Roman family=roman charset=0 pitch=2\n"]; + [expected appendString: @"40 name=Times New Roman Cyr family=roman charset=204 pitch=2\n"]; + [expected appendString: @"31505 name=Times New Roman family=roman charset=0 pitch=2\n"]; + [expected appendString: @"31506 name=Calibri family=swiss charset=0 pitch=2\n"]; + [expected appendString: @"42 name=Times New Roman Greek family=roman charset=161 pitch=2\n"]; + [expected appendString: @"31507 name=Times New Roman family=roman charset=0 pitch=2\n"]; + [expected appendString: @"31508 name=Times New Roman CE family=roman charset=238 pitch=2\n"]; + [expected appendString: @"43 name=Times New Roman Tur family=roman charset=162 pitch=2\n"]; + [expected appendString: @"31509 name=Times New Roman Cyr family=roman charset=204 pitch=2\n"]; + [expected appendString: @"44 name=Times New Roman (Hebrew) family=roman charset=177 pitch=2\n"]; + [expected appendString: @"45 name=Times New Roman (Arabic) family=roman charset=178 pitch=2\n"]; + [expected appendString: @"31511 name=Times New Roman Greek family=roman charset=161 pitch=2\n"]; + [expected appendString: @"46 name=Times New Roman Baltic family=roman charset=186 pitch=2\n"]; + [expected appendString: @"31512 name=Times New Roman Tur family=roman charset=162 pitch=2\n"]; + [expected appendString: @"47 name=Times New Roman (Vietnamese) family=roman charset=163 pitch=2\n"]; + [expected appendString: @"31513 name=Times New Roman (Hebrew) family=roman charset=177 pitch=2\n"]; + [expected appendString: @"31514 name=Times New Roman (Arabic) family=roman charset=178 pitch=2\n"]; + [expected appendString: @"31515 name=Times New Roman Baltic family=roman charset=186 pitch=2\n"]; + [expected appendString: @"31516 name=Times New Roman (Vietnamese) family=roman charset=163 pitch=2\n"]; + [expected appendString: @"31518 name=Times New Roman CE family=roman charset=238 pitch=2\n"]; + [expected appendString: @"31519 name=Times New Roman Cyr family=roman charset=204 pitch=2\n"]; + [expected appendString: @"31521 name=Times New Roman Greek family=roman charset=161 pitch=2\n"]; + [expected appendString: @"31522 name=Times New Roman Tur family=roman charset=162 pitch=2\n"]; + [expected appendString: @"31523 name=Times New Roman (Hebrew) family=roman charset=177 pitch=2\n"]; + [expected appendString: @"31524 name=Times New Roman (Arabic) family=roman charset=178 pitch=2\n"]; + [expected appendString: @"31525 name=Times New Roman Baltic family=roman charset=186 pitch=2\n"]; + [expected appendString: @"31526 name=Times New Roman (Vietnamese) family=roman charset=163 pitch=2\n"]; + [expected appendString: @"31528 name=Cambria CE family=roman charset=238 pitch=2\n"]; + [expected appendString: @"31529 name=Cambria Cyr family=roman charset=204 pitch=2\n"]; + [expected appendString: @"31531 name=Cambria Greek family=roman charset=161 pitch=2\n"]; + [expected appendString: @"31532 name=Cambria Tur family=roman charset=162 pitch=2\n"]; + [expected appendString: @"31535 name=Cambria Baltic family=roman charset=186 pitch=2\n"]; + [expected appendString: @"31536 name=Cambria (Vietnamese) family=roman charset=163 pitch=2\n"]; + [expected appendString: @"31538 name=Times New Roman CE family=roman charset=238 pitch=2\n"]; + [expected appendString: @"31539 name=Times New Roman Cyr family=roman charset=204 pitch=2\n"]; + [expected appendString: @"31541 name=Times New Roman Greek family=roman charset=161 pitch=2\n"]; + [expected appendString: @"31542 name=Times New Roman Tur family=roman charset=162 pitch=2\n"]; + [expected appendString: @"31543 name=Times New Roman (Hebrew) family=roman charset=177 pitch=2\n"]; + [expected appendString: @"31544 name=Times New Roman (Arabic) family=roman charset=178 pitch=2\n"]; + [expected appendString: @"31545 name=Times New Roman Baltic family=roman charset=186 pitch=2\n"]; + [expected appendString: @"31546 name=Times New Roman (Vietnamese) family=roman charset=163 pitch=2\n"]; + [expected appendString: @"31548 name=Times New Roman CE family=roman charset=238 pitch=2\n"]; + [expected appendString: @"31549 name=Times New Roman Cyr family=roman charset=204 pitch=2\n"]; + [expected appendString: @"31551 name=Times New Roman Greek family=roman charset=161 pitch=2\n"]; + [expected appendString: @"31552 name=Times New Roman Tur family=roman charset=162 pitch=2\n"]; + [expected appendString: @"31553 name=Times New Roman (Hebrew) family=roman charset=177 pitch=2\n"]; + [expected appendString: @"31554 name=Times New Roman (Arabic) family=roman charset=178 pitch=2\n"]; + [expected appendString: @"31555 name=Times New Roman Baltic family=roman charset=186 pitch=2\n"]; + [expected appendString: @"31556 name=Times New Roman (Vietnamese) family=roman charset=163 pitch=2\n"]; + [expected appendString: @"31558 name=Times New Roman CE family=roman charset=238 pitch=2\n"]; + [expected appendString: @"31559 name=Times New Roman Cyr family=roman charset=204 pitch=2\n"]; + [expected appendString: @"31561 name=Times New Roman Greek family=roman charset=161 pitch=2\n"]; + [expected appendString: @"31562 name=Times New Roman Tur family=roman charset=162 pitch=2\n"]; + [expected appendString: @"31563 name=Times New Roman (Hebrew) family=roman charset=177 pitch=2\n"]; + [expected appendString: @"31564 name=Times New Roman (Arabic) family=roman charset=178 pitch=2\n"]; + [expected appendString: @"31565 name=Times New Roman Baltic family=roman charset=186 pitch=2\n"]; + [expected appendString: @"31566 name=Times New Roman (Vietnamese) family=roman charset=163 pitch=2\n"]; + [expected appendString: @"31568 name=Calibri CE family=swiss charset=238 pitch=2\n"]; + [expected appendString: @"31569 name=Calibri Cyr family=swiss charset=204 pitch=2\n"]; + [expected appendString: @"31571 name=Calibri Greek family=swiss charset=161 pitch=2\n"]; + [expected appendString: @"31572 name=Calibri Tur family=swiss charset=162 pitch=2\n"]; + [expected appendString: @"31575 name=Calibri Baltic family=swiss charset=186 pitch=2\n"]; + [expected appendString: @"31576 name=Calibri (Vietnamese) family=swiss charset=163 pitch=2\n"]; + [expected appendString: @"31578 name=Times New Roman CE family=roman charset=238 pitch=2\n"]; + [expected appendString: @"31579 name=Times New Roman Cyr family=roman charset=204 pitch=2\n"]; + [expected appendString: @"31581 name=Times New Roman Greek family=roman charset=161 pitch=2\n"]; + [expected appendString: @"31582 name=Times New Roman Tur family=roman charset=162 pitch=2\n"]; + [expected appendString: @"31583 name=Times New Roman (Hebrew) family=roman charset=177 pitch=2\n"]; + [expected appendString: @"31584 name=Times New Roman (Arabic) family=roman charset=178 pitch=2\n"]; + [expected appendString: @"409 name=Calibri CE family=swiss charset=238 pitch=2\n"]; + [expected appendString: @"31585 name=Times New Roman Baltic family=roman charset=186 pitch=2\n"]; + [expected appendString: @"410 name=Calibri Cyr family=swiss charset=204 pitch=2\n"]; + [expected appendString: @"31586 name=Times New Roman (Vietnamese) family=roman charset=163 pitch=2\n"]; + [expected appendString: @"412 name=Calibri Greek family=swiss charset=161 pitch=2\n"]; + [expected appendString: @"413 name=Calibri Tur family=swiss charset=162 pitch=2\n"]; + [expected appendString: @"416 name=Calibri Baltic family=swiss charset=186 pitch=2\n"]; + [expected appendString: @"417 name=Calibri (Vietnamese) family=swiss charset=163 pitch=2\n"]; + + [self checkFonTableParsingOfRTFFile: file + againstExpectedTable: expected]; +} + - (void) test_mini_russian { NSString *file =@"mini_russian.rtf"; @@ -137,4 +288,5 @@ againstExpectedHTML: expected]; } + @end