2
votes

I'm trying to calculate the CRC checksum for an ALAsset. My goal is to save all the CRCs and compare them at a later time to see if the asset has been changed, but every time I generate a CRC for the same asset, I get a different result.

To generate CRC:

#import "CRC32.h"
#import <zlib.h>

@implementation CRC32

+ (uint32_t)CRC32Value:(NSData*)data
{
  uLong crc = crc32(0L, Z_NULL, 0);
  crc = crc32(crc, [data bytes], [data length]);
  return crc;
}

@end

How it is used:

void(^assetEnumerator)(ALAsset *, NSUInteger, BOOL *) = ^(ALAsset *result, NSUInteger index, BOOL *stop) 
  {         
    if(result == nil) 
    {
      return;
    }

    CrawlAssetData *assetData = [[CrawlAssetData alloc] init];
    [assetData setCrc:[CRC32 CRC32Value:[NSData dataWithBytes:&(result) 
                                                       length:sizeof(result)]]];

Here are my results when generating the CRC on different occasions for the same asset:

id: 17575
url: assets-library://asset/asset.JPG?id=BB282CBD-F5B1-4771-B48B-E021224C7384&ext=JPG
filesize: 1394332
crc: 3605102491
creationtime: 2456085.397025

id: 17826
url: assets-library://asset/asset.JPG?id=BB282CBD-F5B1-4771-B48B-E021224C7384&ext=JPG
filesize: 1394332
crc: 1383370697
creationtime: 2456085.397025

As you can see, the filesize and url are the same but the CRC is different.

Am I calculating the CRC wrong? Or should I be using a different part of the ALAsset to generate the CRC? Perhaps some data is different every time an ALAsset is retrieved?

Thanks in advance!

1

1 Answers

1
votes

This line:

[assetData setCrc:[CRC32 CRC32Value:[NSData dataWithBytes:&(result) 
                                                   length:sizeof(result)]]];

...is calculating the CRC of the address of your ALAsset instance, not its data.

You can verify this by splitting the line:

NSData *crcData = [NSData dataWithBytes:&(result) 
                                 length:sizeof(result)];
NSLog( @"crcData length: %d", [crcData length]);
[assetData setCrc:[CRC32 CRC32Value:crcData]];

My guess is that in the output you'll see crcData length: 4.

Based on a follow up comment by the question asker (with a correction) the code to do this is:

ALAssetRepresentation *rep = [result defaultRepresentation];
uint8_t *buffer = malloc(rep.size);
NSUInteger buffered = [rep getBytes:buffer
                         fromOffset:0
                             length:rep.size
                              error:nil];
NSData *data = [NSData dataWithBytesNoCopy:buffer
                                    length:buffered
                              freeWhenDone:YES];   
uint32_t CRC32 = [CRC32 CRC32Value:data];
[assetData setCrc:CRC32];

In particular, note that sizeof(NSData*) (or NSData *a; sizeof(A)) is always going to be the size of a pointer (4 on 32 bit systems like the iPhone, 8 for 64 bit Mac OS X), not the length of the byte data stored in the NSData. There's no normal reason to get the sizeof() a NSObject pointer.