hunk.code_window: #pragma mark - Object lifecycle
   - (instancetype)init {
       self = [super init];
       if (self) {
           // Added to work on Expo, should try to upstream.
           if (!branchInstance) {
               branchInstance = [Branch getInstance];
           }
  
hunk.labels: keep keep keep keep keep replace keep keep keep keep keep
hunk.after_edit:     if (self && [self.bridge.experienceScope.appOwnership isEqualToString:@"standalone"]) {
  
hunk.file_path: ios/versioned-react-native/ABI18_0_0/Exponent/Modules/Api/Standalone/Branch/ABI18_0_0RNBranch.m
hunk.type: replace
file: /**
   * Copyright (c) 2015-present, Facebook, Inc.
   * All rights reserved.
   *
   * This source code is licensed under the BSD-style license found in the
   * LICENSE file in the root directory of this source tree. An additional grant
   * of patent rights can be found in the PATENTS file in the same directory.
   */
  
  #import "ABI17_0_0RCTGIFImageDecoder.h"
  
  #import <ImageIO/ImageIO.h>
  #import <QuartzCore/QuartzCore.h>
  
  #import <ReactABI17_0_0/ABI17_0_0RCTUtils.h>
  
  @implementation ABI17_0_0RCTGIFImageDecoder
  
  ABI17_0_0RCT_EXPORT_MODULE()
  
  - (BOOL)canDecodeImageData:(NSData *)imageData
  {
    char header[7] = {};
    [imageData getBytes:header length:6];
  
    return !strcmp(header, "GIF87a") || !strcmp(header, "GIF89a");
  }
  
  - (ABI17_0_0RCTImageLoaderCancellationBlock)decodeImageData:(NSData *)imageData
                                                size:(CGSize)size
                                               scale:(CGFloat)scale
                                          resizeMode:(ABI17_0_0RCTResizeMode)resizeMode
                                   completionHandler:(ABI17_0_0RCTImageLoaderCompletionBlock)completionHandler
  {
    CGImageSourceRef imageSource = CGImageSourceCreateWithData((CFDataRef)imageData, NULL);
    NSDictionary<NSString *, id> *properties = (__bridge_transfer NSDictionary *)CGImageSourceCopyProperties(imageSource, NULL);
    NSUInteger loopCount = [properties[(id)kCGImagePropertyGIFDictionary][(id)kCGImagePropertyGIFLoopCount] unsignedIntegerValue];
  
    UIImage *image = nil;
    size_t imageCount = CGImageSourceGetCount(imageSource);
    if (imageCount > 1) {
  
      NSTimeInterval duration = 0;
      NSMutableArray<NSNumber *> *delays = [NSMutableArray arrayWithCapacity:imageCount];
      NSMutableArray<id /* CGIMageRef */> *images = [NSMutableArray arrayWithCapacity:imageCount];
      for (size_t i = 0; i < imageCount; i++) {
  
        CGImageRef imageRef = CGImageSourceCreateImageAtIndex(imageSource, i, NULL);
        if (!image) {
          image = [UIImage imageWithCGImage:imageRef scale:scale orientation:UIImageOrientationUp];
        }
  
        NSDictionary<NSString *, id> *frameProperties = (__bridge_transfer NSDictionary *)CGImageSourceCopyPropertiesAtIndex(imageSource, i, NULL);
        NSDictionary<NSString *, id> *frameGIFProperties = frameProperties[(id)kCGImagePropertyGIFDictionary];
  
        const NSTimeInterval kDelayTimeIntervalDefault = 0.1;
        NSNumber *delayTime = frameGIFProperties[(id)kCGImagePropertyGIFUnclampedDelayTime] ?: frameGIFProperties[(id)kCGImagePropertyGIFDelayTime];
        if (delayTime == nil) {
          if (i == 0) {
            delayTime = @(kDelayTimeIntervalDefault);
          } else {
            delayTime = delays[i - 1];
          }
        }
  
        const NSTimeInterval kDelayTimeIntervalMinimum = 0.02;
        if (delayTime.floatValue < (float)kDelayTimeIntervalMinimum - FLT_EPSILON) {
          delayTime = @(kDelayTimeIntervalDefault);
        }
  
        duration += delayTime.doubleValue;
        delays[i] = delayTime;
        images[i] = (__bridge_transfer id)imageRef;
      }
      CFRelease(imageSource);
  
      NSMutableArray<NSNumber *> *keyTimes = [NSMutableArray arrayWithCapacity:delays.count];
      NSTimeInterval runningDuration = 0;
      for (NSNumber *delayNumber in delays) {
        [keyTimes addObject:@(runningDuration / duration)];
        runningDuration += delayNumber.doubleValue;
      }
  
      [keyTimes addObject:@1.0];
  
      // Create animation
      CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"contents"];
      animation.calculationMode = kCAAnimationDiscrete;
      animation.repeatCount = loopCount == 0 ? HUGE_VALF : loopCount;
      animation.keyTimes = keyTimes;
      animation.values = images;
      animation.duration = duration;
      animation.removedOnCompletion = NO;
      image.ReactABI17_0_0KeyframeAnimation = animation;
  
    } else {
  
      // Don't bother creating an animation
      CGImageRef imageRef = CGImageSourceCreateImageAtIndex(imageSource, 0, NULL);
      if (imageRef) {
        image = [UIImage imageWithCGImage:imageRef scale:scale orientation:UIImageOrientationUp];
        CFRelease(imageRef);
      }
      CFRelease(imageSource);
    }
  
    completionHandler(nil, image);
    return ^{};
  }
  
  @end
  