0

I'm developing an app in objective-c that send a file and a Adler32 check sum of that file to a web service.

After I send the file to the web server answers saying that the check sum failed.

This is the code that I use to check sum on objective-c:

//Get Asset NSData
ALAssetRepresentation *rep = [[p objectForKey:@"assetPath"] defaultRepresentation];
Byte *buffer = (Byte*)malloc(rep.size);
NSUInteger buffered = [rep getBytes:buffer fromOffset:0.0 length:rep.size error:nil];
NSData *data = [NSData dataWithBytesNoCopy:buffer length:buffered freeWhenDone:YES];

//I also need a path to the file so I have to save the NSData to a local file
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *localFilePath = [documentsDirectory stringByAppendingPathComponent:@"png"];
[data writeToFile:localFilePath atomically:YES];
NSString *path = localFilePath;

//Now call the Adler
NSLog(@"checksum_fast:%@", [NSString stringWithFormat:@"%u", adler32_fast([data bytes], [data length])]);
NSLog(@"checksum:%@", [NSString stringWithFormat:@"%u", adler32([data bytes], [data length])]);

//Adler Lib
#define MOD_ADLER 65521
#define BUFFER_SIZE 1000

uint32_t adler32_update(uint32_t ck, const unsigned char data) {
  uint32_t a = ck & 0x0ffff, b = (ck >> 16) & 0x0ffff;
  a = (a + data) % MOD_ADLER;
  b = (b + a) % MOD_ADLER;
  return (b << 16) | a;
}

uint32_t adler32(const unsigned char *data, int data_len) {
  uint64_t ck = 1;
  for(int i=0; i<data_len; i++) {
    ck = adler32_update(ck,data[i]);
  }
  return ck;
}

uint32_t adler32_fast(const unsigned char *data, int data_len) {
  uint32_t a = 1, b = 0;
  for(int i=0; i<data_len; i++) {
    a = (a + data[i]) % MOD_ADLER;
    b = (b + a) % MOD_ADLER;
  }
  return (b << 16) | a;
}

And this one is the code of the C# web service:

//It use ICSharpCode.SharpZipLib.dll    
byte[] buff = null;
FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read);
BinaryReader br = new BinaryReader(fs);
long numBytes = new FileInfo(path).Length;
buff = br.ReadBytes((int)numBytes);

Adler32 adler = new Adler32();
adler.Reset();
adler.Update(buff, 0, buff.Length);
fs.Close();
fs.Dispose();
br.Close();
buff = null;
return Convert.ToString(adler.Value, 16);

Do any one knows why I'm getting to different check sum results?

Testing file: http://we.tl/gjqSj43238

Adler32 C#: 701ea682 (1881056898)

Adler32 Obj-C: 70100C51 (1880099921)

Thanks!

Tony
  • 287
  • 5
  • 19

1 Answers1

2

Most importantly, you spelled Adler wrong. Your constant should be MOD_ADLER, not MOD_ALDER.

You have not provided all of your code, so I don't know what you set that constant to.

Your code is not "fast" as the name claims, since you do the modulo operations every time. There's no point to having the two nested loops there if you're not going to defer the modulo operations.

1 & 0xFFFF seems silly, since that is always 1.

Your error is that you initialize b to 1. It should be initialized to 0.

Ah, I see another error: you need to use unsigned char, not char for your data arrays.

I recommend that you copy the adler32() implementation in zlib.

Mark Adler
  • 101,978
  • 13
  • 118
  • 158
  • Thanks Mark, the name of MOD_ADLER was fixed, the value is 65521. Also I paste more of the code, there is all. – Tony Aug 28 '13 at 14:15
  • Now your code will give the correct check value, though will be slow. – Mark Adler Aug 28 '13 at 14:26
  • The result are different in each code, I try an only tool that calculate Adler32, C# code have the same result but in obj-c I'm getting other. C#: 1881056898 Obj-c: 1880099921 Online tool: 1881056898 May the problem is when I pass [data bytes] to the function, it expects const char *data. – Tony Aug 28 '13 at 14:56
  • Hi Mark, It doesn't work, Now that I made the change, I'm getting 3243175871. Thanks. – Tony Sep 02 '13 at 14:00
  • Mark Question Updated with the file I'm using and also from where come the NSData. – Tony Sep 02 '13 at 20:29