Run-length encoding/Objective-C: Difference between revisions
(moved from Run-length encoding) |
m (modernize) |
||
Line 12: | Line 12: | ||
NSMutableArray *counters; |
NSMutableArray *counters; |
||
} |
} |
||
⚫ | |||
+ (id)alloc; |
|||
- (instancetype)initWithData: (NSData *)data; |
|||
- (id)init; |
|||
⚫ | |||
- (void)dealloc; |
|||
- (void)addByte: (char)aByte; |
- (void)addByte: (char)aByte; |
||
- (void)addByte: (char)aByte repeated: (int)repetitionCount; |
- (void)addByte: (char)aByte repeated: (int)repetitionCount; |
||
Line 27: | Line 24: | ||
@implementation RCRunLengthEncoder |
@implementation RCRunLengthEncoder |
||
+ ( |
+ (instancetype)encoderWithData: (NSData *)data |
||
{ |
{ |
||
return |
return [[self alloc] initWithData: data]; |
||
} |
} |
||
- ( |
- (instancetype)initWithData: (NSData *)data |
||
{ |
{ |
||
if ((self = [self init]) != nil) { |
if ((self = [self init]) != nil) { |
||
Line 40: | Line 37: | ||
} |
} |
||
- ( |
- (instancetype)init |
||
{ |
{ |
||
if ((self = [super init]) != nil) { |
if ((self = [super init]) != nil) { |
||
Line 47: | Line 44: | ||
} |
} |
||
return self; |
return self; |
||
} |
|||
- (void)dealloc |
|||
{ |
|||
[counters release]; |
|||
[contents release]; |
|||
[super dealloc]; |
|||
} |
} |
||
Line 64: | Line 54: | ||
{ |
{ |
||
if ( ([contents count] == 0) || ([[contents lastObject] charValue] != aByte) ) { |
if ( ([contents count] == 0) || ([[contents lastObject] charValue] != aByte) ) { |
||
[contents addObject: |
[contents addObject: @(aByte)]; |
||
[counters addObject: |
[counters addObject: @(repetitionCount)]; |
||
} else { |
} else { |
||
int a = [[counters lastObject] intValue]; |
|||
[counters removeLastObject]; |
[counters removeLastObject]; |
||
[counters addObject: |
[counters addObject: @(a + repetitionCount)]; |
||
([a intValue] + repetitionCount) ]]; |
|||
} |
} |
||
} |
} |
||
Line 98: | Line 87: | ||
for(i=0; i < [contents count]; i++) { |
for(i=0; i < [contents count]; i++) { |
||
char c = |
char c = [contents[i] charValue]; |
||
int n = |
int n = [counters[i] intValue]; |
||
memset(buf, c, 256); |
memset(buf, c, 256); |
||
while ( n > 0 ) { |
while ( n > 0 ) { |
||
Line 106: | Line 95: | ||
} |
} |
||
} |
} |
||
return |
return d; |
||
} |
} |
||
@end</lang> |
@end</lang> |
||
Line 147: | Line 136: | ||
for(i=0; i < [counters count]; i++) { |
for(i=0; i < [counters count]; i++) { |
||
char c = |
char c = [contents[i] charValue]; |
||
int howMany = |
int howMany = [counters[i] intValue]; |
||
if ( literalCount == 128 ) { |
if ( literalCount == 128 ) { |
||
buf[0] = 0; |
buf[0] = 0; |
||
Line 175: | Line 164: | ||
} |
} |
||
} |
} |
||
return |
return r; |
||
} |
} |
||
@end</lang> |
@end</lang> |
||
Line 185: | Line 174: | ||
int main() |
int main() |
||
{ |
{ |
||
@autoreleasepool { |
|||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; |
|||
codecRLE *enc = [[codecRLE alloc] |
codecRLE *enc = [[codecRLE alloc] |
||
initWithData: [NSData dataWithBytes: s |
initWithData: [NSData dataWithBytes: s |
||
length: strlen(s)] ]; |
length: strlen(s)] ]; |
||
NSData *repr = [enc encode]; |
NSData *repr = [enc encode]; |
||
fwrite([repr bytes], 1, [repr length], stdout); |
fwrite([repr bytes], 1, [repr length], stdout); |
||
[enc release]; |
|||
enc = [[codecRLE alloc] init]; |
enc = [[codecRLE alloc] init]; |
||
[enc decode: repr]; |
[enc decode: repr]; |
||
NSData *d = [enc data]; |
NSData *d = [enc data]; |
||
fwrite([d bytes], 1, [d length], stdout); |
fwrite([d bytes], 1, [d length], stdout); |
||
[enc release]; |
|||
} |
|||
[pool release]; |
|||
return EXIT_SUCCESS; |
return EXIT_SUCCESS; |
||
}</lang> |
}</lang> |
Latest revision as of 07:20, 27 February 2014
The class RCRunLengthEncoder represents internally data with which it was feeded as pair character - repetition counter: it does not implement a binary representation of itself; it is left to another class, so that different input/output encodings are possible starting from the same class.
<lang objc>#import <Foundation/Foundation.h>
@interface RCRunLengthEncoder : NSObject {
NSMutableArray *contents; NSMutableArray *counters;
} + (instancetype)encoderWithData: (NSData *)data; - (instancetype)initWithData: (NSData *)data; - (void)addByte: (char)aByte; - (void)addByte: (char)aByte repeated: (int)repetitionCount; - (void)addData: (NSData *)data; - (NSData *)data; - (NSArray *)counters; - (NSArray *)contents; @end
@implementation RCRunLengthEncoder
+ (instancetype)encoderWithData: (NSData *)data
{
return [[self alloc] initWithData: data];
}
- (instancetype)initWithData: (NSData *)data {
if ((self = [self init]) != nil) { [self addData: data]; } return self;
}
- (instancetype)init {
if ((self = [super init]) != nil) { contents = [[NSMutableArray alloc] init]; counters = [[NSMutableArray alloc] init]; } return self;
}
- (void)addByte: (char)aByte {
[self addByte: aByte repeated: 1];
}
- (void)addByte: (char)aByte repeated: (int)repetitionCount {
if ( ([contents count] == 0) || ([[contents lastObject] charValue] != aByte) ) { [contents addObject: @(aByte)]; [counters addObject: @(repetitionCount)]; } else { int a = [[counters lastObject] intValue]; [counters removeLastObject]; [counters addObject: @(a + repetitionCount)]; }
}
- (void)addData: (NSData *)data {
const char *d = [data bytes]; NSUInteger i; for(i=0; i < [data length]; i++) [self addByte: d[i]];
}
- (NSArray *)contents {
return contents;
}
- (NSArray *)counters {
return counters;
}
- (NSData *)data {
NSMutableData *d = [[NSMutableData alloc] initWithCapacity: 256]; char buf[256]; int i;
for(i=0; i < [contents count]; i++) { char c = [contents[i] charValue]; int n = [counters[i] intValue]; memset(buf, c, 256); while ( n > 0 ) { [d appendBytes: buf length: MIN(256, n)]; n -= 256; } } return d;
} @end</lang>
The class codecRLE is derived from the previous, adding the methods that allow to binary encode the data internally held, and to create a internal representation from the encoded data. The specification here used are:
- byte N >= 128, then the next byte must be repeated N-128 times (if N-128 is 0, the the byte must be repeated 128 times)
- byte N < 128, then the next N bytes must be taken as they are (if N is 0, the next 128 bytes are literal)
<lang objc>@interface codecRLE : RCRunLengthEncoder - (NSData *)encode; - (void)decode: (NSData *)enc; @end
@implementation codecRLE - (void)decode: (NSData *)enc {
const char *buf = [enc bytes]; int i;
for(i = 0; i < [enc length]; ) { if ( (buf[i] & 0x80) != 0) { [self addByte: buf[i+1] repeated: ( ((buf[i]&0x7f) == 0) ? 128 : (buf[i]&0x7f) ) ]; i += 2; } else { int rc = (buf[i] == 0) ? 128 : buf[i]; [self addData: [NSData dataWithBytes: &buf[i+1] length: rc]]; i += rc + 1; } }
}
- (NSData *)encode {
int literalCount=0; int i; char buf[129];
NSMutableData *r = [[NSMutableData alloc] initWithCapacity: 256];
for(i=0; i < [counters count]; i++) { char c = [contents[i] charValue]; int howMany = [counters[i] intValue]; if ( literalCount == 128 ) { buf[0] = 0; [r appendBytes: buf length: 129]; literalCount = 0; } if ( howMany == 1 ) { buf[literalCount+1] = c; literalCount++; } else { if ( literalCount > 0 ) {
buf[0] = literalCount & 0x7f; [r appendBytes: buf length: (literalCount+1) ]; literalCount = 0;
} buf[1] = c; while( howMany > 127 ) {
buf[0] = 0x80; [r appendBytes: buf length: 2]; howMany -= 128;
} if (howMany > 0) {
buf[0] = howMany | 0x80; [r appendBytes: buf length: 2];
} } } return r;
} @end</lang>
Usage example:
<lang objc>const char *s = "WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWBWWWWWWWWWWWWWW";
int main() {
@autoreleasepool {
codecRLE *enc = [[codecRLE alloc]
initWithData: [NSData dataWithBytes: s length: strlen(s)] ];
NSData *repr = [enc encode]; fwrite([repr bytes], 1, [repr length], stdout);
enc = [[codecRLE alloc] init]; [enc decode: repr]; NSData *d = [enc data]; fwrite([d bytes], 1, [d length], stdout);
} return EXIT_SUCCESS;
}</lang>
Notes
- The code is not deeply tested yet