add .gitignore
This commit is contained in:
BIN
msext/Class/AMapLocationKit.framework/AMapLocationKit
Executable file
BIN
msext/Class/AMapLocationKit.framework/AMapLocationKit
Executable file
Binary file not shown.
26
msext/Class/AMapLocationKit.framework/Headers/AMapGeoFenceError.h
Executable file
26
msext/Class/AMapLocationKit.framework/Headers/AMapGeoFenceError.h
Executable file
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// AMapGeoFenceError.h
|
||||
// AMapLocationKit
|
||||
//
|
||||
// Created by eidan on 16/12/15.
|
||||
// Copyright © 2016年 Amap. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef AMapGeoFenceError_h
|
||||
#define AMapGeoFenceError_h
|
||||
|
||||
|
||||
///AMapGeoFence errorDomain
|
||||
extern NSString * const AMapGeoFenceErrorDomain;
|
||||
|
||||
///地理围栏错误码
|
||||
typedef NS_ENUM(NSInteger, AMapGeoFenceErrorCode) {
|
||||
AMapGeoFenceErrorUnknown = 1, ///< 未知错误
|
||||
AMapGeoFenceErrorInvalidParameter = 2, ///< 参数错误
|
||||
AMapGeoFenceErrorFailureConnection = 3, ///< 网络连接异常
|
||||
AMapGeoFenceErrorFailureAuth = 4, ///< 鉴权失败
|
||||
AMapGeoFenceErrorNoValidFence = 5, ///< 无可用围栏
|
||||
AMapGeoFenceErroFailureLocating = 6, ///< 定位错误
|
||||
};
|
||||
|
||||
#endif /* AMapGeoFenceError_h */
|
||||
211
msext/Class/AMapLocationKit.framework/Headers/AMapGeoFenceManager.h
Executable file
211
msext/Class/AMapLocationKit.framework/Headers/AMapGeoFenceManager.h
Executable file
@@ -0,0 +1,211 @@
|
||||
//
|
||||
// AMapGeoFenceManager.h
|
||||
// AMapLocationKit
|
||||
//
|
||||
// Created by hanxiaoming on 16/12/5.
|
||||
// Copyright © 2016年 Amap. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "AMapGeoFenceRegionObj.h"
|
||||
|
||||
// 以下类涉及的坐标需要使用高德坐标系坐标(GCJ02)
|
||||
|
||||
@protocol AMapGeoFenceManagerDelegate;
|
||||
|
||||
///地理围栏监听状态类型
|
||||
typedef NS_OPTIONS(NSUInteger, AMapGeoFenceActiveAction)
|
||||
{
|
||||
AMapGeoFenceActiveActionNone = 0, ///< 不进行监听
|
||||
AMapGeoFenceActiveActionInside = 1 << 0, ///< 在范围内
|
||||
AMapGeoFenceActiveActionOutside = 1 << 1, ///< 在范围外
|
||||
AMapGeoFenceActiveActionStayed = 1 << 2, ///< 停留(在范围内超过10分钟)
|
||||
};
|
||||
|
||||
///地理围栏任务状态类型
|
||||
typedef NS_OPTIONS(NSUInteger, AMapGeoFenceRegionActiveStatus)
|
||||
{
|
||||
AMapGeoFenceRegionActiveUNMonitor = 0, ///< 未注册
|
||||
AMapGeoFenceRegionActiveMonitoring = 1 << 0, ///< 正在监控
|
||||
AMapGeoFenceRegionActivePaused = 1 << 1, ///< 暂停监控
|
||||
};
|
||||
|
||||
///地理围栏管理类(since 2.3.0)
|
||||
@interface AMapGeoFenceManager : NSObject
|
||||
|
||||
|
||||
///实现了 AMapGeoFenceManagerDelegate 协议的类指针。
|
||||
@property (nonatomic, weak) id<AMapGeoFenceManagerDelegate> delegate;
|
||||
|
||||
|
||||
///需要进行通知的行为,默认为AMapGeoFenceActiveActionInside。
|
||||
@property (nonatomic, assign) AMapGeoFenceActiveAction activeAction;
|
||||
|
||||
|
||||
///指定定位是否会被系统自动暂停。默认为NO。
|
||||
@property (nonatomic, assign) BOOL pausesLocationUpdatesAutomatically;
|
||||
|
||||
|
||||
///是否允许后台定位。默认为NO。只在iOS 9.0及之后起作用。设置为YES的时候必须保证 Background Modes 中的 Location updates 处于选中状态,否则会抛出异常。
|
||||
@property (nonatomic, assign) BOOL allowsBackgroundLocationUpdates;
|
||||
|
||||
///检测是否存在虚拟定位风险,默认为NO,即不检测。 \n如果设置为YES,检测到风险后,会通过amapGeoFenceManager:didGeoFencesStatusChangedForRegion:customID:error: 的error给出风险提示,error的格式为error.domain==AMapGeoFenceErrorDomain; error.code==AMapGeoFenceErroFailureLocating;
|
||||
@property (nonatomic, assign) BOOL detectRiskOfFakeLocation;
|
||||
|
||||
|
||||
/**
|
||||
* @brief 添加一个圆形围栏
|
||||
* @param center 围栏的中心点经纬度坐标
|
||||
* @param radius 围栏的半径,单位:米,要求大于0
|
||||
* @param customID 用户自定义ID,可选,SDK原值返回
|
||||
*/
|
||||
- (void)addCircleRegionForMonitoringWithCenter:(CLLocationCoordinate2D)center radius:(CLLocationDistance)radius customID:(NSString *)customID;
|
||||
|
||||
|
||||
/**
|
||||
* @brief 根据经纬度坐标数据添加一个闭合的多边形围栏,点与点之间按顺序尾部相连, 第一个点与最后一个点相连
|
||||
* @param coordinates 经纬度坐标点数据,coordinates对应的内存会拷贝,调用者负责该内存的释放
|
||||
* @param count 经纬度坐标点的个数,不可小于3个
|
||||
* @param customID 用户自定义ID,可选,SDK原值返回
|
||||
*/
|
||||
- (void)addPolygonRegionForMonitoringWithCoordinates:(CLLocationCoordinate2D *)coordinates count:(NSInteger)count customID:(NSString *)customID;
|
||||
|
||||
|
||||
/**
|
||||
* @brief 根据要查询的关键字,类型,城市等信息,添加一个或者多个POI地理围栏
|
||||
* @param keyword 要查询的关键字,多个关键字用“|”分割,必填,keyword和type两者至少必选其一
|
||||
* @param type 要查询的POI类型,多个类型用“|”分割,必填,keyword和type两者至少必选其一,具体分类编码和规则详见: http://lbs.amap.com/api/webservice/guide/api/search/#text
|
||||
* @param city 要查询的城市
|
||||
* @param size 要查询的数据的条数,(0,25],传入<=0的值为10,传入大于25的值为25,默认10
|
||||
* @param customID 用户自定义ID,可选,SDK原值返回
|
||||
*/
|
||||
- (void)addKeywordPOIRegionForMonitoringWithKeyword:(NSString *)keyword POIType:(NSString *)type city:(NSString *)city size:(NSInteger)size customID:(NSString *)customID;
|
||||
|
||||
|
||||
/**
|
||||
* @brief 根据要查询的点的经纬度,搜索半径等信息,添加一个或者多个POI围栏
|
||||
* @param locationPoint 点的经纬度坐标,必填
|
||||
* @param aroundRadius 查询半径,单位:米,(0,50000],超出范围取3000,默认3000
|
||||
* @param keyword 要查询的关键字,多个关键字用“|”分割,可选
|
||||
* @param type 要查询的POI类型,多个类型用“|”分割,可选
|
||||
* @param size 要查询的数据的条数,(0,25],传入<=0的值为10,传入大于25的值为25,默认10
|
||||
* @param customID 用户自定义ID,可选,SDK原值返回
|
||||
*/
|
||||
- (void)addAroundPOIRegionForMonitoringWithLocationPoint:(CLLocationCoordinate2D)locationPoint aroundRadius:(NSInteger)aroundRadius keyword:(NSString *)keyword POIType:(NSString *)type size:(NSInteger)size customID:(NSString *)customID;
|
||||
|
||||
|
||||
/**
|
||||
* @brief 根据要查询的行政区域关键字,添加一个或者多个行政区域围栏
|
||||
* @param districtName 行政区域关键字,必填,只支持单个关键词语:行政区名称、citycode、adcode,规则详见: http://lbs.amap.com/api/webservice/guide/api/district/#district
|
||||
* @param customID 用户自定义ID,可选,SDK原值返回
|
||||
*/
|
||||
- (void)addDistrictRegionForMonitoringWithDistrictName:(NSString *)districtName customID:(NSString *)customID;
|
||||
|
||||
/**
|
||||
* @brief 获取指定围栏的运行状态
|
||||
* @param region 要获取运行状态的围栏
|
||||
* @return 返回指定围栏的运行状态
|
||||
*/
|
||||
- (AMapGeoFenceRegionActiveStatus)statusWithGeoFenceRegion:(AMapGeoFenceRegion *)region;
|
||||
|
||||
/**
|
||||
* @brief 根据customID获得所有已经注册的围栏,如果customID传nil,则返回全部已注册围栏
|
||||
* @param customID 用户执行添加围栏函数时传入的customID
|
||||
* @return 获得的围栏构成的数组,如果没有结果,返回nil
|
||||
*/
|
||||
- (NSArray *)geoFenceRegionsWithCustomID:(NSString *)customID;
|
||||
|
||||
/**
|
||||
* @brief 根据customID获得所有正在监控的围栏,如果customID传nil,则返回全部正在监控的围栏
|
||||
* @param customID 用户执行添加围栏函数时传入的customID
|
||||
* @return 获得的围栏构成的数组,如果没有结果,返回nil
|
||||
*/
|
||||
- (NSArray *)monitoringGeoFenceRegionsWithCustomID:(NSString *)customID;
|
||||
|
||||
/**
|
||||
* @brief 根据customID获得所有已经暂停的围栏,如果customID传nil,则返回全部已经暂停的围栏
|
||||
* @param customID 用户执行添加围栏函数时传入的customID
|
||||
* @return 获得的围栏构成的数组,如果没有结果,返回nil
|
||||
*/
|
||||
- (NSArray *)pausedGeoFenceRegionsWithCustomID:(NSString *)customID;
|
||||
|
||||
|
||||
/**
|
||||
* @brief 暂停指定customID的围栏
|
||||
* @param customID 用户执行添加围栏函数时传入的customID
|
||||
* @return 返回被暂停围栏的数组,如果没有围栏被暂停,返回nil
|
||||
*/
|
||||
- (NSArray *)pauseGeoFenceRegionsWithCustomID:(NSString *)customID;
|
||||
|
||||
|
||||
/**
|
||||
* @brief 暂停指定围栏
|
||||
* @param region 要暂停监控的围栏
|
||||
* @return 返回指定围栏是否被暂停,如果指定围栏没有注册,则返回NO
|
||||
*/
|
||||
- (BOOL)pauseTheGeoFenceRegion:(AMapGeoFenceRegion *)region;
|
||||
|
||||
/**
|
||||
* @brief 根据customID开始监控已经暂停的围栏
|
||||
* @param customID 用户执行添加围栏函数时传入的customID
|
||||
* @return 返回开始监控的围栏构成的数组
|
||||
*/
|
||||
- (NSArray *)startGeoFenceRegionsWithCustomID:(NSString *)customID;
|
||||
|
||||
/**
|
||||
* @brief 开始监控指定围栏
|
||||
* @param region 要开始监控的围栏
|
||||
* @return 返回指定围栏是否开始监控,如果指定围栏没有注册,则返回NO
|
||||
*/
|
||||
- (BOOL)startTheGeoFenceRegion:(AMapGeoFenceRegion *)region;
|
||||
|
||||
/**
|
||||
* @brief 移除指定围栏
|
||||
* @param region 要停止监控的围栏
|
||||
*/
|
||||
- (void)removeTheGeoFenceRegion:(AMapGeoFenceRegion *)region;
|
||||
|
||||
|
||||
/**
|
||||
* @brief 移除指定customID的围栏
|
||||
* @param customID 用户执行添加围栏函数时传入的customID
|
||||
*/
|
||||
- (void)removeGeoFenceRegionsWithCustomID:(NSString *)customID;
|
||||
|
||||
|
||||
/**
|
||||
* @brief 移除所有围栏
|
||||
*/
|
||||
- (void)removeAllGeoFenceRegions;
|
||||
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
///地理围栏代理协议(since 2.3.0),该协议定义了获取地理围栏相关回调方法,包括添加、状态改变等。
|
||||
@protocol AMapGeoFenceManagerDelegate <NSObject>
|
||||
|
||||
@optional
|
||||
|
||||
|
||||
/**
|
||||
* @brief 添加地理围栏完成后的回调,成功与失败都会调用
|
||||
* @param manager 地理围栏管理类
|
||||
* @param regions 成功添加的一个或多个地理围栏构成的数组
|
||||
* @param customID 用户执行添加围栏函数时传入的customID
|
||||
* @param error 添加失败的错误信息
|
||||
*/
|
||||
- (void)amapGeoFenceManager:(AMapGeoFenceManager *)manager didAddRegionForMonitoringFinished:(NSArray <AMapGeoFenceRegion *> *)regions customID:(NSString *)customID error:(NSError *)error;
|
||||
|
||||
|
||||
/**
|
||||
* @brief 地理围栏状态改变时回调,当围栏状态的值发生改变,定位失败都会调用
|
||||
* @param manager 地理围栏管理类
|
||||
* @param region 状态改变的地理围栏
|
||||
* @param customID 用户执行添加围栏函数时传入的customID
|
||||
* @param error 错误信息,如定位相关的错误
|
||||
*/
|
||||
- (void)amapGeoFenceManager:(AMapGeoFenceManager *)manager didGeoFencesStatusChangedForRegion:(AMapGeoFenceRegion *)region customID:(NSString *)customID error:(NSError *)error;
|
||||
|
||||
@end
|
||||
120
msext/Class/AMapLocationKit.framework/Headers/AMapGeoFenceRegionObj.h
Executable file
120
msext/Class/AMapLocationKit.framework/Headers/AMapGeoFenceRegionObj.h
Executable file
@@ -0,0 +1,120 @@
|
||||
//
|
||||
// AMapGeoFenceRegionObj.h
|
||||
// AMapLocationKit
|
||||
//
|
||||
// Created by hanxiaoming on 16/12/5.
|
||||
// Copyright © 2016年 Amap. All rights reserved.
|
||||
//
|
||||
|
||||
#import "AMapLocationCommonObj.h"
|
||||
|
||||
|
||||
///AMapGeoFence Region State
|
||||
typedef NS_ENUM(NSInteger, AMapGeoFenceRegionStatus)
|
||||
{
|
||||
AMapGeoFenceRegionStatusUnknown = 0, ///< 未知
|
||||
AMapGeoFenceRegionStatusInside = 1, ///< 在范围内
|
||||
AMapGeoFenceRegionStatusOutside = 2, ///< 在范围外
|
||||
AMapGeoFenceRegionStatusStayed = 3, ///< 停留(在范围内超过10分钟)
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSInteger, AMapGeoFenceRegionType)
|
||||
{
|
||||
AMapGeoFenceRegionTypeCircle = 0, /// 圆形地理围栏
|
||||
AMapGeoFenceRegionTypePolygon = 1, /// 多边形地理围栏
|
||||
AMapGeoFenceRegionTypePOI = 2, /// 兴趣点(POI)地理围栏
|
||||
AMapGeoFenceRegionTypeDistrict = 3, /// 行政区划地理围栏
|
||||
};
|
||||
|
||||
#pragma mark - AMapGeoFenceRegion
|
||||
|
||||
|
||||
///地理围栏基类,不可直接使用。(since 2.3.0)
|
||||
@interface AMapGeoFenceRegion : NSObject<NSCopying>
|
||||
|
||||
|
||||
///AMapGeoFenceRegion的唯一标识符
|
||||
@property (nonatomic, copy, readonly) NSString *identifier;
|
||||
|
||||
|
||||
///用户自定义ID,可为nil。
|
||||
@property (nonatomic, copy, readonly) NSString *customID;
|
||||
|
||||
|
||||
///坐标点和围栏的关系,比如用户的位置和围栏的关系
|
||||
@property (nonatomic, assign) AMapGeoFenceRegionStatus fenceStatus;
|
||||
|
||||
///用户自定义ID,可为nil。
|
||||
@property (nonatomic, assign) AMapGeoFenceRegionType regionType;
|
||||
|
||||
///缓存最近获取的定位信息,可能会存在延时,可为nil,会在获取定位时更新
|
||||
@property (nonatomic, copy) CLLocation *currentLocation;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
#pragma mark - AMapLocationCircleRegion
|
||||
|
||||
|
||||
///圆形地理围栏(since 2.3.0)
|
||||
@interface AMapGeoFenceCircleRegion : AMapGeoFenceRegion
|
||||
|
||||
|
||||
///中心点的经纬度坐标
|
||||
@property (nonatomic, readonly) CLLocationCoordinate2D center;
|
||||
|
||||
|
||||
///半径,单位:米
|
||||
@property (nonatomic, readonly) CLLocationDistance radius;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
#pragma mark -AMapGeoFencePolygonRegion
|
||||
|
||||
|
||||
///多边形地理围栏(since 2.3.0)
|
||||
@interface AMapGeoFencePolygonRegion : AMapGeoFenceRegion
|
||||
|
||||
|
||||
///经纬度坐标点数据
|
||||
@property (nonatomic, readonly) CLLocationCoordinate2D *coordinates;
|
||||
|
||||
|
||||
///经纬度坐标点的个数
|
||||
@property (nonatomic, readonly) NSInteger count;
|
||||
|
||||
|
||||
@end
|
||||
|
||||
|
||||
#pragma mark -AMapGeoFencePOIRegion
|
||||
|
||||
|
||||
///兴趣点(POI)地理围栏(since 2.3.0)
|
||||
@interface AMapGeoFencePOIRegion : AMapGeoFenceCircleRegion
|
||||
|
||||
|
||||
///POI信息
|
||||
@property (nonatomic, strong, readonly) AMapLocationPOIItem *POIItem;
|
||||
|
||||
|
||||
@end
|
||||
|
||||
|
||||
#pragma mark -AMapGeoFenceDistrictRegion
|
||||
|
||||
|
||||
///行政区划地理围栏(since 2.3.0)
|
||||
@interface AMapGeoFenceDistrictRegion : AMapGeoFenceRegion
|
||||
|
||||
|
||||
///行政区域信息
|
||||
@property (nonatomic, strong, readonly) AMapLocationDistrictItem *districtItem;
|
||||
|
||||
|
||||
///行政区域轮廓坐标点,每个行政区可能有多个模块,每个模块的坐标点数组由AMapLocationPoint构成
|
||||
@property (nonatomic, copy, readonly) NSArray <NSArray<AMapLocationPoint *> *> *polylinePoints;
|
||||
|
||||
|
||||
@end
|
||||
194
msext/Class/AMapLocationKit.framework/Headers/AMapLocationCommonObj.h
Executable file
194
msext/Class/AMapLocationKit.framework/Headers/AMapLocationCommonObj.h
Executable file
@@ -0,0 +1,194 @@
|
||||
//
|
||||
// AMapLocationCommonObj.h
|
||||
// AMapLocationKit
|
||||
//
|
||||
// Created by AutoNavi on 15/10/22.
|
||||
// Copyright © 2015年 Amap. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <CoreLocation/CoreLocation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
|
||||
///AMapLocation errorDomain
|
||||
extern NSString * const AMapLocationErrorDomain;
|
||||
|
||||
///AMapLocation errorCode
|
||||
typedef NS_ENUM(NSInteger, AMapLocationErrorCode)
|
||||
{
|
||||
AMapLocationErrorUnknown = 1, ///<未知错误
|
||||
AMapLocationErrorLocateFailed = 2, ///<定位错误
|
||||
AMapLocationErrorReGeocodeFailed = 3, ///<逆地理错误
|
||||
AMapLocationErrorTimeOut = 4, ///<超时
|
||||
AMapLocationErrorCanceled = 5, ///<取消
|
||||
AMapLocationErrorCannotFindHost = 6, ///<找不到主机
|
||||
AMapLocationErrorBadURL = 7, ///<URL异常
|
||||
AMapLocationErrorNotConnectedToInternet = 8,///<连接异常
|
||||
AMapLocationErrorCannotConnectToHost = 9, ///<服务器连接失败
|
||||
AMapLocationErrorRegionMonitoringFailure=10,///<地理围栏错误
|
||||
AMapLocationErrorRiskOfFakeLocation = 11, ///<存在虚拟定位风险
|
||||
};
|
||||
|
||||
///AMapLocation Region State
|
||||
typedef NS_ENUM(NSInteger, AMapLocationRegionState)
|
||||
{
|
||||
AMapLocationRegionStateUnknow = 0, ///<未知
|
||||
AMapLocationRegionStateInside = 1, ///<在范围内
|
||||
AMapLocationRegionStateOutside = 2, ///<在范围外
|
||||
};
|
||||
|
||||
///AMapLocation Region Language
|
||||
typedef NS_ENUM(NSInteger, AMapLocationReGeocodeLanguage)
|
||||
{
|
||||
AMapLocationReGeocodeLanguageDefault = 0, ///<默认,根据地区选择语言
|
||||
AMapLocationReGeocodeLanguageChinse = 1, ///<中文
|
||||
AMapLocationReGeocodeLanguageEnglish = 2, ///<英文
|
||||
};
|
||||
|
||||
///逆地理信息
|
||||
@interface AMapLocationReGeocode : NSObject<NSCopying,NSCoding>
|
||||
|
||||
///格式化地址
|
||||
@property (nonatomic, copy) NSString *formattedAddress;
|
||||
|
||||
///国家
|
||||
@property (nonatomic, copy) NSString *country;
|
||||
|
||||
///省/直辖市
|
||||
@property (nonatomic, copy) NSString *province;
|
||||
|
||||
///市
|
||||
@property (nonatomic, copy) NSString *city;
|
||||
|
||||
///区
|
||||
@property (nonatomic, copy) NSString *district;
|
||||
|
||||
///乡镇
|
||||
@property (nonatomic, copy) NSString *township __attribute__((deprecated("该字段从v2.2.0版本起不再返回数据,建议您使用AMapSearchKit的逆地理功能获取.")));
|
||||
|
||||
///社区
|
||||
@property (nonatomic, copy) NSString *neighborhood __attribute__((deprecated("该字段从v2.2.0版本起不再返回数据,建议您使用AMapSearchKit的逆地理功能获取.")));
|
||||
|
||||
///建筑
|
||||
@property (nonatomic, copy) NSString *building __attribute__((deprecated("该字段从v2.2.0版本起不再返回数据,建议您使用AMapSearchKit的逆地理功能获取.")));
|
||||
|
||||
///城市编码
|
||||
@property (nonatomic, copy) NSString *citycode;
|
||||
|
||||
///区域编码
|
||||
@property (nonatomic, copy) NSString *adcode;
|
||||
|
||||
///街道名称
|
||||
@property (nonatomic, copy) NSString *street;
|
||||
|
||||
///门牌号
|
||||
@property (nonatomic, copy) NSString *number;
|
||||
|
||||
///兴趣点名称
|
||||
@property (nonatomic, copy) NSString *POIName;
|
||||
|
||||
///所属兴趣点名称
|
||||
@property (nonatomic, copy) NSString *AOIName;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - AMapLocationPoint
|
||||
|
||||
///经纬度坐标点对象
|
||||
@interface AMapLocationPoint : NSObject<NSCopying,NSCoding>
|
||||
|
||||
///纬度
|
||||
@property (nonatomic, assign) CGFloat latitude;
|
||||
|
||||
///经度
|
||||
@property (nonatomic, assign) CGFloat longitude;
|
||||
|
||||
/**
|
||||
* @brief AMapNaviPoint类对象的初始化函数
|
||||
* @param lat 纬度
|
||||
* @param lon 经度
|
||||
* @return AMapNaviPoint类对象id
|
||||
*/
|
||||
+ (AMapLocationPoint *)locationWithLatitude:(CGFloat)lat longitude:(CGFloat)lon;
|
||||
|
||||
@end
|
||||
|
||||
///POI信息
|
||||
@interface AMapLocationPOIItem : NSObject <NSCopying, NSCoding>
|
||||
|
||||
///id
|
||||
@property (nonatomic, copy) NSString *pId;
|
||||
|
||||
///名称
|
||||
@property (nonatomic, copy) NSString *name;
|
||||
|
||||
///类型
|
||||
@property (nonatomic, copy) NSString *type;
|
||||
|
||||
///类型编码
|
||||
@property (nonatomic, copy) NSString *typeCode;
|
||||
|
||||
///地址信息
|
||||
@property (nonatomic, copy) NSString *address;
|
||||
|
||||
///经纬度
|
||||
@property (nonatomic, strong) AMapLocationPoint *location;
|
||||
|
||||
///电话号码
|
||||
@property (nonatomic, copy) NSString *tel;
|
||||
|
||||
///省份
|
||||
@property (nonatomic, copy) NSString *province;
|
||||
|
||||
///城市
|
||||
@property (nonatomic, copy) NSString *city;
|
||||
|
||||
///区
|
||||
@property (nonatomic, copy) NSString *district;
|
||||
|
||||
@end
|
||||
|
||||
///行政区域信息
|
||||
@interface AMapLocationDistrictItem : NSObject <NSCopying, NSCoding>
|
||||
|
||||
///城市编码
|
||||
@property (nonatomic, copy) NSString *cityCode;
|
||||
|
||||
///区域编码
|
||||
@property (nonatomic, copy) NSString *districtCode;
|
||||
|
||||
///区名
|
||||
@property (nonatomic, copy) NSString *district;
|
||||
|
||||
///行政区域轮廓坐标点,每个行政区可能有多个模块,每个模块的坐标点数组由AMapLocationPoint构成
|
||||
@property (nonatomic, copy) NSArray <NSArray<AMapLocationPoint *> *> *polylinePoints;
|
||||
|
||||
@end
|
||||
|
||||
///AMapLocation CoordinateType
|
||||
typedef NS_ENUM(NSUInteger, AMapLocationCoordinateType)
|
||||
{
|
||||
AMapLocationCoordinateTypeBaidu = 0, ///<Baidu
|
||||
AMapLocationCoordinateTypeMapBar, ///<MapBar
|
||||
AMapLocationCoordinateTypeMapABC, ///<MapABC
|
||||
AMapLocationCoordinateTypeSoSoMap, ///<SoSoMap
|
||||
AMapLocationCoordinateTypeAliYun, ///<AliYun
|
||||
AMapLocationCoordinateTypeGoogle, ///<Google
|
||||
AMapLocationCoordinateTypeGPS, ///<GPS
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 转换目标经纬度为高德坐标系
|
||||
* @param coordinate 待转换的经纬度
|
||||
* @param type 坐标系类型
|
||||
* @return 高德坐标系经纬度
|
||||
*/
|
||||
FOUNDATION_EXTERN CLLocationCoordinate2D AMapLocationCoordinateConvert(CLLocationCoordinate2D coordinate, AMapLocationCoordinateType type);
|
||||
|
||||
/**
|
||||
* @brief 判断目标经纬度是否在大陆以及港、澳地区。输入参数为高德坐标系。
|
||||
* @param coordinate 待判断的目标经纬度
|
||||
* @return 是否在大陆以及港、澳地区
|
||||
*/
|
||||
FOUNDATION_EXTERN BOOL AMapLocationDataAvailableForCoordinate(CLLocationCoordinate2D coordinate);
|
||||
17
msext/Class/AMapLocationKit.framework/Headers/AMapLocationKit.h
Executable file
17
msext/Class/AMapLocationKit.framework/Headers/AMapLocationKit.h
Executable file
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// AMapLocationKit.h
|
||||
// AMapLocationKit
|
||||
//
|
||||
// Created by AutoNavi on 15/10/22.
|
||||
// Copyright © 2015年 Amap. All rights reserved.
|
||||
//
|
||||
|
||||
#import <AMapLocationKit/AMapLocationVersion.h>
|
||||
|
||||
#import <AMapLocationKit/AMapLocationManager.h>
|
||||
#import <AMapLocationKit/AMapLocationCommonObj.h>
|
||||
#import <AMapLocationKit/AMapLocationRegionObj.h>
|
||||
|
||||
#import <AMapLocationKit/AMapGeoFenceRegionObj.h>
|
||||
#import <AMapLocationKit/AMapGeoFenceManager.h>
|
||||
#import <AMapLocationKit/AMapGeoFenceError.h>
|
||||
208
msext/Class/AMapLocationKit.framework/Headers/AMapLocationManager.h
Executable file
208
msext/Class/AMapLocationKit.framework/Headers/AMapLocationManager.h
Executable file
@@ -0,0 +1,208 @@
|
||||
//
|
||||
// AMapLocationManager.h
|
||||
// AMapLocationKit
|
||||
//
|
||||
// Created by AutoNavi on 15/10/22.
|
||||
// Copyright © 2015年 Amap. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "AMapLocationCommonObj.h"
|
||||
#import "AMapLocationRegionObj.h"
|
||||
|
||||
/**
|
||||
* @brief AMapLocatingCompletionBlock 单次定位返回Block
|
||||
* @param location 定位信息
|
||||
* @param regeocode 逆地理信息
|
||||
* @param error 错误信息,参考 AMapLocationErrorCode
|
||||
*/
|
||||
typedef void (^AMapLocatingCompletionBlock)(CLLocation *location, AMapLocationReGeocode *regeocode, NSError *error);
|
||||
|
||||
@protocol AMapLocationManagerDelegate;
|
||||
|
||||
#pragma mark - AMapLocationManager
|
||||
|
||||
///AMapLocationManager类。初始化之前请设置 AMapServices 中的apikey(例如:[AMapServices sharedServices].apiKey = @"您的key"),否则将无法正常使用服务.
|
||||
@interface AMapLocationManager : NSObject
|
||||
|
||||
///实现了 AMapLocationManagerDelegate 协议的类指针。
|
||||
@property (nonatomic, weak) id<AMapLocationManagerDelegate> delegate;
|
||||
|
||||
///设定定位的最小更新距离。单位米,默认为 kCLDistanceFilterNone,表示只要检测到设备位置发生变化就会更新位置信息。
|
||||
@property(nonatomic, assign) CLLocationDistance distanceFilter;
|
||||
|
||||
///设定期望的定位精度。单位米,默认为 kCLLocationAccuracyBest。定位服务会尽可能去获取满足desiredAccuracy的定位结果,但不保证一定会得到满足期望的结果。 \n注意:设置为kCLLocationAccuracyBest或kCLLocationAccuracyBestForNavigation时,单次定位会在达到locationTimeout设定的时间后,将时间内获取到的最高精度的定位结果返回。
|
||||
@property(nonatomic, assign) CLLocationAccuracy desiredAccuracy;
|
||||
|
||||
///指定定位是否会被系统自动暂停。默认为NO。
|
||||
@property(nonatomic, assign) BOOL pausesLocationUpdatesAutomatically;
|
||||
|
||||
///是否允许后台定位。默认为NO。只在iOS 9.0及之后起作用。设置为YES的时候必须保证 Background Modes 中的 Location updates 处于选中状态,否则会抛出异常。由于iOS系统限制,需要在定位未开始之前或定位停止之后,修改该属性的值才会有效果。
|
||||
@property(nonatomic, assign) BOOL allowsBackgroundLocationUpdates;
|
||||
|
||||
///指定单次定位超时时间,默认为10s。最小值是2s。注意单次定位请求前设置。注意: 单次定位超时时间从确定了定位权限(非kCLAuthorizationStatusNotDetermined状态)后开始计算。
|
||||
@property(nonatomic, assign) NSInteger locationTimeout;
|
||||
|
||||
///指定单次定位逆地理超时时间,默认为5s。最小值是2s。注意单次定位请求前设置。
|
||||
@property(nonatomic, assign) NSInteger reGeocodeTimeout;
|
||||
|
||||
///连续定位是否返回逆地理信息,默认NO。
|
||||
@property (nonatomic, assign) BOOL locatingWithReGeocode;
|
||||
|
||||
// 逆地址语言类型,默认是AMapLocationRegionLanguageDefault
|
||||
@property (nonatomic, assign) AMapLocationReGeocodeLanguage reGeocodeLanguage;
|
||||
|
||||
///获取被监控的region集合。
|
||||
@property (nonatomic, readonly, copy) NSSet *monitoredRegions;
|
||||
|
||||
///检测是否存在虚拟定位风险,默认为NO,不检测。 \n注意:设置为YES时,单次定位通过 AMapLocatingCompletionBlock 的error给出虚拟定位风险提示;连续定位通过 amapLocationManager:didFailWithError: 方法的error给出虚拟定位风险提示。error格式为error.domain==AMapLocationErrorDomain; error.code==AMapLocationErrorRiskOfFakeLocation;
|
||||
@property (nonatomic, assign) BOOL detectRiskOfFakeLocation;
|
||||
|
||||
/**
|
||||
* @brief 设备是否支持方向识别
|
||||
* @return YES:设备支持方向识别 ; NO:设备不支持支持方向识别
|
||||
*/
|
||||
+ (BOOL)headingAvailable;
|
||||
|
||||
/**
|
||||
* @brief 开始获取设备朝向,如果设备支持方向识别,则会通过代理回调方法
|
||||
*/
|
||||
- (void)startUpdatingHeading;
|
||||
|
||||
/**
|
||||
* @brief 停止获取设备朝向
|
||||
*/
|
||||
- (void)stopUpdatingHeading;
|
||||
|
||||
/**
|
||||
* @brief 停止设备朝向校准显示
|
||||
*/
|
||||
- (void)dismissHeadingCalibrationDisplay;
|
||||
|
||||
/**
|
||||
* @brief 单次定位。如果当前正在连续定位,调用此方法将会失败,返回NO。\n该方法将会根据设定的 desiredAccuracy 去获取定位信息。如果获取的定位信息精确度低于 desiredAccuracy ,将会持续的等待定位信息,直到超时后通过completionBlock返回精度最高的定位信息。\n可以通过 stopUpdatingLocation 方法去取消正在进行的单次定位请求。
|
||||
* @param withReGeocode 是否带有逆地理信息(获取逆地理信息需要联网)
|
||||
* @param completionBlock 单次定位完成后的Block
|
||||
* @return 是否成功添加单次定位Request
|
||||
*/
|
||||
- (BOOL)requestLocationWithReGeocode:(BOOL)withReGeocode completionBlock:(AMapLocatingCompletionBlock)completionBlock;
|
||||
|
||||
/**
|
||||
* @brief 开始连续定位。调用此方法会cancel掉所有的单次定位请求。
|
||||
*/
|
||||
- (void)startUpdatingLocation;
|
||||
|
||||
/**
|
||||
* @brief 停止连续定位。调用此方法会cancel掉所有的单次定位请求,可以用来取消单次定位。
|
||||
*/
|
||||
- (void)stopUpdatingLocation;
|
||||
|
||||
/**
|
||||
* @brief 开始监控指定的region。如果已经存在相同identifier的region,则之前的region将会被移除。对 AMapLocationCircleRegion 类实例,将会优先监控radius小的region。
|
||||
* @param region 要被监控的范围
|
||||
*/
|
||||
- (void)startMonitoringForRegion:(AMapLocationRegion *)region __attribute__((deprecated("请使用AMapGeoFenceManager")));
|
||||
|
||||
/**
|
||||
* @brief 停止监控指定的region
|
||||
* @param region 要停止监控的范围
|
||||
*/
|
||||
- (void)stopMonitoringForRegion:(AMapLocationRegion *)region __attribute__((deprecated("请使用AMapGeoFenceManager")));
|
||||
|
||||
/**
|
||||
* @brief 查询一个region的当前状态。查询结果通过amapLocationManager:didDetermineState:forRegion:回调返回
|
||||
* @param region 要查询的region
|
||||
*/
|
||||
- (void)requestStateForRegion:(AMapLocationRegion *)region __attribute__((deprecated("请使用AMapGeoFenceManager")));
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - AMapLocationManagerDelegate
|
||||
|
||||
|
||||
///AMapLocationManagerDelegate 协议定义了发生错误时的错误回调方法,连续定位的回调方法等。
|
||||
@protocol AMapLocationManagerDelegate <NSObject>
|
||||
|
||||
@optional
|
||||
|
||||
/**
|
||||
* @brief 当定位发生错误时,会调用代理的此方法。
|
||||
* @param manager 定位 AMapLocationManager 类。
|
||||
* @param error 返回的错误,参考 CLError 。
|
||||
*/
|
||||
- (void)amapLocationManager:(AMapLocationManager *)manager didFailWithError:(NSError *)error;
|
||||
|
||||
/**
|
||||
* @brief 连续定位回调函数.注意:本方法已被废弃,如果实现了amapLocationManager:didUpdateLocation:reGeocode:方法,则本方法将不会回调。
|
||||
* @param manager 定位 AMapLocationManager 类。
|
||||
* @param location 定位结果。
|
||||
*/
|
||||
- (void)amapLocationManager:(AMapLocationManager *)manager didUpdateLocation:(CLLocation *)location;
|
||||
|
||||
/**
|
||||
* @brief 连续定位回调函数.注意:如果实现了本方法,则定位信息不会通过amapLocationManager:didUpdateLocation:方法回调。
|
||||
* @param manager 定位 AMapLocationManager 类。
|
||||
* @param location 定位结果。
|
||||
* @param reGeocode 逆地理信息。
|
||||
*/
|
||||
- (void)amapLocationManager:(AMapLocationManager *)manager didUpdateLocation:(CLLocation *)location reGeocode:(AMapLocationReGeocode *)reGeocode;
|
||||
|
||||
/**
|
||||
* @brief 定位权限状态改变时回调函数
|
||||
* @param manager 定位 AMapLocationManager 类。
|
||||
* @param status 定位权限状态。
|
||||
*/
|
||||
- (void)amapLocationManager:(AMapLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status;
|
||||
|
||||
/**
|
||||
* @brief 是否显示设备朝向校准
|
||||
* @param manager 定位 AMapLocationManager 类。
|
||||
* @return 是否显示设备朝向校准
|
||||
*/
|
||||
- (BOOL)amapLocationManagerShouldDisplayHeadingCalibration:(AMapLocationManager *)manager;
|
||||
|
||||
/**
|
||||
* @brief 设备方向改变时回调函数
|
||||
* @param manager 定位 AMapLocationManager 类。
|
||||
* @param newHeading 设备朝向。
|
||||
*/
|
||||
- (void)amapLocationManager:(AMapLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading;
|
||||
|
||||
/**
|
||||
* @brief 开始监控region回调函数
|
||||
* @param manager 定位 AMapLocationManager 类。
|
||||
* @param region 开始监控的region。
|
||||
*/
|
||||
- (void)amapLocationManager:(AMapLocationManager *)manager didStartMonitoringForRegion:(AMapLocationRegion *)region __attribute__((deprecated("请使用AMapGeoFenceManager")));
|
||||
|
||||
/**
|
||||
* @brief 进入region回调函数
|
||||
* @param manager 定位 AMapLocationManager 类。
|
||||
* @param region 进入的region。
|
||||
*/
|
||||
- (void)amapLocationManager:(AMapLocationManager *)manager didEnterRegion:(AMapLocationRegion *)region __attribute__((deprecated("请使用AMapGeoFenceManager")));
|
||||
|
||||
/**
|
||||
* @brief 离开region回调函数
|
||||
* @param manager 定位 AMapLocationManager 类。
|
||||
* @param region 离开的region。
|
||||
*/
|
||||
- (void)amapLocationManager:(AMapLocationManager *)manager didExitRegion:(AMapLocationRegion *)region __attribute__((deprecated("请使用AMapGeoFenceManager")));
|
||||
|
||||
/**
|
||||
* @brief 查询region状态回调函数
|
||||
* @param manager 定位 AMapLocationManager 类。
|
||||
* @param state 查询的region的状态。
|
||||
* @param region 查询的region。
|
||||
*/
|
||||
- (void)amapLocationManager:(AMapLocationManager *)manager didDetermineState:(AMapLocationRegionState)state forRegion:(AMapLocationRegion *)region __attribute__((deprecated("请使用AMapGeoFenceManager")));
|
||||
|
||||
/**
|
||||
* @brief 监控region失败回调函数
|
||||
* @param manager 定位 AMapLocationManager 类。
|
||||
* @param region 失败的region。
|
||||
* @param error 错误信息,参考 AMapLocationErrorCode 。
|
||||
*/
|
||||
- (void)amapLocationManager:(AMapLocationManager *)manager monitoringDidFailForRegion:(AMapLocationRegion *)region withError:(NSError *)error __attribute__((deprecated("请使用AMapGeoFenceManager")));
|
||||
|
||||
@end
|
||||
90
msext/Class/AMapLocationKit.framework/Headers/AMapLocationRegionObj.h
Executable file
90
msext/Class/AMapLocationKit.framework/Headers/AMapLocationRegionObj.h
Executable file
@@ -0,0 +1,90 @@
|
||||
//
|
||||
// AMapLocationRegionObj.h
|
||||
// AMapLocationKit
|
||||
//
|
||||
// Created by AutoNavi on 15/11/27.
|
||||
// Copyright © 2015年 Amap. All rights reserved.
|
||||
//
|
||||
|
||||
#import "AMapLocationCommonObj.h"
|
||||
|
||||
// 以下类涉及的坐标需要使用高德坐标系坐标(GCJ02)
|
||||
|
||||
#pragma mark - AMapLocationRegion
|
||||
|
||||
|
||||
///AMapLocationRegion类,该类提供范围类的基本信息,并无具体实现,不要直接使用。
|
||||
@interface AMapLocationRegion : NSObject<NSCopying>
|
||||
|
||||
///AMapLocationRegion的identifier
|
||||
@property (nonatomic, copy, readonly) NSString *identifier;
|
||||
|
||||
///当进入region范围时是否通知,默认YES
|
||||
@property (nonatomic, assign) BOOL notifyOnEntry;
|
||||
|
||||
///当离开region范围时是否通知,默认YES
|
||||
@property (nonatomic, assign) BOOL notifyOnExit;
|
||||
|
||||
/**
|
||||
* @brief 初始化方法
|
||||
* @param identifier 唯一标识符,必填,不可为nil
|
||||
*/
|
||||
- (instancetype)initWithIdentifier:(NSString *)identifier;
|
||||
|
||||
/**
|
||||
* @brief 坐标点是否在范围内
|
||||
* @param coordinate 要判断的坐标点
|
||||
* @return 是否在范围内
|
||||
*/
|
||||
- (BOOL)containsCoordinate:(CLLocationCoordinate2D)coordinate;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - AMapLocationCircleRegion
|
||||
|
||||
|
||||
///AMapLocationCircleRegion类,定义一个圆形范围。
|
||||
@interface AMapLocationCircleRegion : AMapLocationRegion
|
||||
|
||||
///中心点的经纬度坐标
|
||||
@property (nonatomic, readonly) CLLocationCoordinate2D center;
|
||||
|
||||
///半径,单位:米
|
||||
@property (nonatomic, readonly) CLLocationDistance radius;
|
||||
|
||||
/**
|
||||
* @brief 根据中心点和半径生成圆形范围
|
||||
* @param center 中心点的经纬度坐标
|
||||
* @param radius 半径,单位:米
|
||||
* @param identifier 唯一标识符,必填,不可为nil
|
||||
* @return AMapLocationCircleRegion类实例
|
||||
*/
|
||||
- (instancetype)initWithCenter:(CLLocationCoordinate2D)center radius:(CLLocationDistance)radius identifier:(NSString *)identifier;
|
||||
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark - AMapLocationPolygonRegion
|
||||
|
||||
|
||||
///AMapLocationCircleRegion类,定义一个闭合多边形范围,点与点之间按顺序尾部相连, 第一个点与最后一个点相连。
|
||||
@interface AMapLocationPolygonRegion : AMapLocationRegion
|
||||
|
||||
///经纬度坐标点数据
|
||||
@property (nonatomic, readonly) CLLocationCoordinate2D *coordinates;
|
||||
|
||||
///经纬度坐标点的个数
|
||||
@property (nonatomic, readonly) NSInteger count;
|
||||
|
||||
/**
|
||||
* @brief 根据经纬度坐标数据生成闭合多边形范围
|
||||
* @param coordinates 经纬度坐标点数据,coordinates对应的内存会拷贝,调用者负责该内存的释放
|
||||
* @param count 经纬度坐标点的个数,不可小于3个
|
||||
* @param identifier 唯一标识符,必填,不可为nil
|
||||
* @return AMapLocationCircleRegion类实例
|
||||
*/
|
||||
- (instancetype)initWithCoordinates:(CLLocationCoordinate2D *)coordinates count:(NSInteger)count identifier:(NSString *)identifier;
|
||||
|
||||
|
||||
|
||||
@end
|
||||
26
msext/Class/AMapLocationKit.framework/Headers/AMapLocationVersion.h
Executable file
26
msext/Class/AMapLocationKit.framework/Headers/AMapLocationVersion.h
Executable file
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// AMapLoctionVersion.h
|
||||
// AMapLocationKit
|
||||
//
|
||||
// Created by AutoNavi on 16/1/22.
|
||||
// Copyright © 2016年 Amap. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <AMapFoundationKit/AMapFoundationVersion.h>
|
||||
|
||||
#ifndef AMapLoctionVersion_h
|
||||
#define AMapLoctionVersion_h
|
||||
|
||||
#define AMapLocationVersionNumber 20600
|
||||
#define AMapLocationFoundationVersionMinRequired 10400
|
||||
|
||||
// 依赖库版本检测
|
||||
#if AMapFoundationVersionNumber < AMapLocationFoundationVersionMinRequired
|
||||
#error "The AMapFoundationKit version is less than minimum required, please update! Any questions please to visit http://lbs.amap.com"
|
||||
#endif
|
||||
|
||||
FOUNDATION_EXTERN NSString * const AMapLocationVersion;
|
||||
FOUNDATION_EXTERN NSString * const AMapLocationName;
|
||||
|
||||
#endif /* AMapLoctionVersion_h */
|
||||
1
msext/Class/AMapLocationKit.framework/version.txt
Executable file
1
msext/Class/AMapLocationKit.framework/version.txt
Executable file
@@ -0,0 +1 @@
|
||||
2.6.0+loc.1b6dee7
|
||||
16
msext/Class/Common/APIKey.h
Executable file
16
msext/Class/Common/APIKey.h
Executable file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// APIKey.h
|
||||
// OfficialDemoLoc
|
||||
//
|
||||
// Created by AutoNavi on 15-9-14.
|
||||
// Copyright (c) 2013年 AutoNavi. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef OfficialDemoLoc_APIKey_h
|
||||
#define OfficialDemoLoc_APIKey_h
|
||||
|
||||
/* 使用高德地图API,请注册Key,注册地址:http://lbs.amap.com/console/key */
|
||||
|
||||
const static NSString *APIKey = @"b0d4a8e3fcbbcc0dd96283b7df6a4494";
|
||||
|
||||
#endif
|
||||
125
msext/Class/Common/ASIHttpRequest/.svn/all-wcprops
Executable file
125
msext/Class/Common/ASIHttpRequest/.svn/all-wcprops
Executable file
@@ -0,0 +1,125 @@
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 96
|
||||
/svn/com.mouee.ios/!svn/ver/133/release/trunk/MoueeIOS/Release/Release/ThirdParty/ASIHttpRequest
|
||||
END
|
||||
ASIHTTPRequest.m
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 113
|
||||
/svn/com.mouee.ios/!svn/ver/133/release/trunk/MoueeIOS/Release/Release/ThirdParty/ASIHttpRequest/ASIHTTPRequest.m
|
||||
END
|
||||
ASICacheDelegate.h
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 115
|
||||
/svn/com.mouee.ios/!svn/ver/133/release/trunk/MoueeIOS/Release/Release/ThirdParty/ASIHttpRequest/ASICacheDelegate.h
|
||||
END
|
||||
ASINetworkQueue.h
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 114
|
||||
/svn/com.mouee.ios/!svn/ver/133/release/trunk/MoueeIOS/Release/Release/ThirdParty/ASIHttpRequest/ASINetworkQueue.h
|
||||
END
|
||||
ASIDataDecompressor.h
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 118
|
||||
/svn/com.mouee.ios/!svn/ver/133/release/trunk/MoueeIOS/Release/Release/ThirdParty/ASIHttpRequest/ASIDataDecompressor.h
|
||||
END
|
||||
ASIAuthenticationDialog.h
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 122
|
||||
/svn/com.mouee.ios/!svn/ver/133/release/trunk/MoueeIOS/Release/Release/ThirdParty/ASIHttpRequest/ASIAuthenticationDialog.h
|
||||
END
|
||||
ASIProgressDelegate.h
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 118
|
||||
/svn/com.mouee.ios/!svn/ver/133/release/trunk/MoueeIOS/Release/Release/ThirdParty/ASIHttpRequest/ASIProgressDelegate.h
|
||||
END
|
||||
ASIDownloadCache.m
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 115
|
||||
/svn/com.mouee.ios/!svn/ver/133/release/trunk/MoueeIOS/Release/Release/ThirdParty/ASIHttpRequest/ASIDownloadCache.m
|
||||
END
|
||||
ASINetworkQueue.m
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 114
|
||||
/svn/com.mouee.ios/!svn/ver/133/release/trunk/MoueeIOS/Release/Release/ThirdParty/ASIHttpRequest/ASINetworkQueue.m
|
||||
END
|
||||
ASIDataDecompressor.m
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 118
|
||||
/svn/com.mouee.ios/!svn/ver/133/release/trunk/MoueeIOS/Release/Release/ThirdParty/ASIHttpRequest/ASIDataDecompressor.m
|
||||
END
|
||||
ASIAuthenticationDialog.m
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 122
|
||||
/svn/com.mouee.ios/!svn/ver/133/release/trunk/MoueeIOS/Release/Release/ThirdParty/ASIHttpRequest/ASIAuthenticationDialog.m
|
||||
END
|
||||
ASIFormDataRequest.h
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 117
|
||||
/svn/com.mouee.ios/!svn/ver/133/release/trunk/MoueeIOS/Release/Release/ThirdParty/ASIHttpRequest/ASIFormDataRequest.h
|
||||
END
|
||||
ASIFormDataRequest.m
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 117
|
||||
/svn/com.mouee.ios/!svn/ver/133/release/trunk/MoueeIOS/Release/Release/ThirdParty/ASIHttpRequest/ASIFormDataRequest.m
|
||||
END
|
||||
ASIInputStream.h
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 113
|
||||
/svn/com.mouee.ios/!svn/ver/133/release/trunk/MoueeIOS/Release/Release/ThirdParty/ASIHttpRequest/ASIInputStream.h
|
||||
END
|
||||
ASIHTTPRequestConfig.h
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 119
|
||||
/svn/com.mouee.ios/!svn/ver/133/release/trunk/MoueeIOS/Release/Release/ThirdParty/ASIHttpRequest/ASIHTTPRequestConfig.h
|
||||
END
|
||||
ASIInputStream.m
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 113
|
||||
/svn/com.mouee.ios/!svn/ver/133/release/trunk/MoueeIOS/Release/Release/ThirdParty/ASIHttpRequest/ASIInputStream.m
|
||||
END
|
||||
ASIHTTPRequestDelegate.h
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 121
|
||||
/svn/com.mouee.ios/!svn/ver/133/release/trunk/MoueeIOS/Release/Release/ThirdParty/ASIHttpRequest/ASIHTTPRequestDelegate.h
|
||||
END
|
||||
ASIDataCompressor.h
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 116
|
||||
/svn/com.mouee.ios/!svn/ver/133/release/trunk/MoueeIOS/Release/Release/ThirdParty/ASIHttpRequest/ASIDataCompressor.h
|
||||
END
|
||||
ASIHTTPRequest.h
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 113
|
||||
/svn/com.mouee.ios/!svn/ver/133/release/trunk/MoueeIOS/Release/Release/ThirdParty/ASIHttpRequest/ASIHTTPRequest.h
|
||||
END
|
||||
ASIDownloadCache.h
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 115
|
||||
/svn/com.mouee.ios/!svn/ver/133/release/trunk/MoueeIOS/Release/Release/ThirdParty/ASIHttpRequest/ASIDownloadCache.h
|
||||
END
|
||||
ASIDataCompressor.m
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 116
|
||||
/svn/com.mouee.ios/!svn/ver/133/release/trunk/MoueeIOS/Release/Release/ThirdParty/ASIHttpRequest/ASIDataCompressor.m
|
||||
END
|
||||
708
msext/Class/Common/ASIHttpRequest/.svn/entries
Executable file
708
msext/Class/Common/ASIHttpRequest/.svn/entries
Executable file
@@ -0,0 +1,708 @@
|
||||
10
|
||||
|
||||
dir
|
||||
158
|
||||
https://192.168.1.108/svn/com.mouee.ios/release/trunk/MoueeIOS/Release/Release/ThirdParty/ASIHttpRequest
|
||||
https://192.168.1.108/svn/com.mouee.ios
|
||||
|
||||
|
||||
|
||||
2012-08-25T07:41:16.910000Z
|
||||
133
|
||||
liwei
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
edcb6c81-38c0-4a4f-bab3-e02b3f82dc25
|
||||
|
||||
ASIHTTPRequest.m
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2012-03-07T19:00:34.000000Z
|
||||
e531997a6084a6d359b96e30128e010d
|
||||
2012-08-25T07:41:16.910000Z
|
||||
133
|
||||
liwei
|
||||
has-props
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
184635
|
||||
|
||||
ASICacheDelegate.h
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2012-03-07T19:00:34.000000Z
|
||||
d7eecaf775884aeec419c1dd6c912b75
|
||||
2012-08-25T07:41:16.910000Z
|
||||
133
|
||||
liwei
|
||||
has-props
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
5151
|
||||
|
||||
ASINetworkQueue.h
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2012-03-07T19:00:34.000000Z
|
||||
ac37fbe46f31892abdb9c43b6a249a84
|
||||
2012-08-25T07:41:16.910000Z
|
||||
133
|
||||
liwei
|
||||
has-props
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
4621
|
||||
|
||||
ASIDataDecompressor.h
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2012-03-07T19:00:34.000000Z
|
||||
b880ed0fc75896beb31676009dc308c6
|
||||
2012-08-25T07:41:16.910000Z
|
||||
133
|
||||
liwei
|
||||
has-props
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
1699
|
||||
|
||||
ASIAuthenticationDialog.h
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2012-03-07T19:00:34.000000Z
|
||||
09ef51b980d0a69951c9c703722e97e8
|
||||
2012-08-25T07:41:16.910000Z
|
||||
133
|
||||
liwei
|
||||
has-props
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
1107
|
||||
|
||||
ASIProgressDelegate.h
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2012-03-07T19:00:34.000000Z
|
||||
64de5fd485dbff9e73cce2a127dc32c3
|
||||
2012-08-25T07:41:16.910000Z
|
||||
133
|
||||
liwei
|
||||
has-props
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
1656
|
||||
|
||||
ASIDownloadCache.m
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2012-03-07T19:00:34.000000Z
|
||||
042086ef61b2bf5f2a66b6e028287a89
|
||||
2012-08-25T07:41:16.910000Z
|
||||
133
|
||||
liwei
|
||||
has-props
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
17761
|
||||
|
||||
ASINetworkQueue.m
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2012-03-07T19:00:34.000000Z
|
||||
569c65f4d7e0c056c5b4ca01d947a741
|
||||
2012-08-25T07:41:16.910000Z
|
||||
133
|
||||
liwei
|
||||
has-props
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
11405
|
||||
|
||||
ASIDataDecompressor.m
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2012-03-07T19:00:34.000000Z
|
||||
8a44db8841a09d03799cd45e88ab50f8
|
||||
2012-08-25T07:41:16.910000Z
|
||||
133
|
||||
liwei
|
||||
has-props
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
6422
|
||||
|
||||
ASIAuthenticationDialog.m
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2012-03-07T19:00:34.000000Z
|
||||
22eb729c54171d2f7ca520c31cef8161
|
||||
2012-08-25T07:41:16.910000Z
|
||||
133
|
||||
liwei
|
||||
has-props
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
16202
|
||||
|
||||
ASIFormDataRequest.h
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2012-03-07T19:00:34.000000Z
|
||||
4908e5f063ee8462fbd762118d1170b8
|
||||
2012-08-25T07:41:16.910000Z
|
||||
133
|
||||
liwei
|
||||
has-props
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
2693
|
||||
|
||||
ASIFormDataRequest.m
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2012-03-07T19:00:34.000000Z
|
||||
87407eed67b1863eca711047c94f2edb
|
||||
2012-08-25T07:41:16.910000Z
|
||||
133
|
||||
liwei
|
||||
has-props
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
11266
|
||||
|
||||
ASIInputStream.h
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2012-03-07T19:00:34.000000Z
|
||||
7ca1696b1598349cc98a65f602df591c
|
||||
2012-08-25T07:41:16.910000Z
|
||||
133
|
||||
liwei
|
||||
has-props
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
969
|
||||
|
||||
ASIHTTPRequestConfig.h
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2012-03-07T19:00:34.000000Z
|
||||
5b18b6c019e4caef9a7062531a5e6fb3
|
||||
2012-08-25T07:41:16.910000Z
|
||||
133
|
||||
liwei
|
||||
has-props
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
1297
|
||||
|
||||
ASIInputStream.m
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2012-03-07T19:00:34.000000Z
|
||||
0f064667b55c487982cfdd23134864cb
|
||||
2012-08-25T07:41:16.910000Z
|
||||
133
|
||||
liwei
|
||||
has-props
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
3122
|
||||
|
||||
ASIHTTPRequestDelegate.h
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2012-03-07T19:00:34.000000Z
|
||||
680deee08e40ed1ac50e18b33bd52347
|
||||
2012-08-25T07:41:16.910000Z
|
||||
133
|
||||
liwei
|
||||
has-props
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
1598
|
||||
|
||||
ASIDataCompressor.h
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2012-03-07T19:00:34.000000Z
|
||||
a4028d2d356cda229eacaca26981622f
|
||||
2012-08-25T07:41:16.910000Z
|
||||
133
|
||||
liwei
|
||||
has-props
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
1836
|
||||
|
||||
ASIHTTPRequest.h
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2012-03-07T19:00:34.000000Z
|
||||
bda45d2c138c16845bc900370fbb7bd4
|
||||
2012-08-25T07:41:16.910000Z
|
||||
133
|
||||
liwei
|
||||
has-props
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
45045
|
||||
|
||||
ASIDownloadCache.h
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2012-03-07T19:00:34.000000Z
|
||||
e597b80f6e26c3fe263612a879088e3d
|
||||
2012-08-25T07:41:16.910000Z
|
||||
133
|
||||
liwei
|
||||
has-props
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
1996
|
||||
|
||||
ASIDataCompressor.m
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2012-03-07T19:00:34.000000Z
|
||||
862e169e15d182c2ee3c5a3ace39c449
|
||||
2012-08-25T07:41:16.910000Z
|
||||
133
|
||||
liwei
|
||||
has-props
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
6755
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
K 14
|
||||
svn:executable
|
||||
V 1
|
||||
*
|
||||
END
|
||||
@@ -0,0 +1,5 @@
|
||||
K 14
|
||||
svn:executable
|
||||
V 1
|
||||
*
|
||||
END
|
||||
@@ -0,0 +1,5 @@
|
||||
K 14
|
||||
svn:executable
|
||||
V 1
|
||||
*
|
||||
END
|
||||
@@ -0,0 +1,5 @@
|
||||
K 14
|
||||
svn:executable
|
||||
V 1
|
||||
*
|
||||
END
|
||||
@@ -0,0 +1,5 @@
|
||||
K 14
|
||||
svn:executable
|
||||
V 1
|
||||
*
|
||||
END
|
||||
@@ -0,0 +1,5 @@
|
||||
K 14
|
||||
svn:executable
|
||||
V 1
|
||||
*
|
||||
END
|
||||
@@ -0,0 +1,5 @@
|
||||
K 14
|
||||
svn:executable
|
||||
V 1
|
||||
*
|
||||
END
|
||||
@@ -0,0 +1,5 @@
|
||||
K 14
|
||||
svn:executable
|
||||
V 1
|
||||
*
|
||||
END
|
||||
@@ -0,0 +1,5 @@
|
||||
K 14
|
||||
svn:executable
|
||||
V 1
|
||||
*
|
||||
END
|
||||
@@ -0,0 +1,5 @@
|
||||
K 14
|
||||
svn:executable
|
||||
V 1
|
||||
*
|
||||
END
|
||||
@@ -0,0 +1,5 @@
|
||||
K 14
|
||||
svn:executable
|
||||
V 1
|
||||
*
|
||||
END
|
||||
@@ -0,0 +1,5 @@
|
||||
K 14
|
||||
svn:executable
|
||||
V 1
|
||||
*
|
||||
END
|
||||
@@ -0,0 +1,5 @@
|
||||
K 14
|
||||
svn:executable
|
||||
V 1
|
||||
*
|
||||
END
|
||||
@@ -0,0 +1,5 @@
|
||||
K 14
|
||||
svn:executable
|
||||
V 1
|
||||
*
|
||||
END
|
||||
@@ -0,0 +1,5 @@
|
||||
K 14
|
||||
svn:executable
|
||||
V 1
|
||||
*
|
||||
END
|
||||
@@ -0,0 +1,5 @@
|
||||
K 14
|
||||
svn:executable
|
||||
V 1
|
||||
*
|
||||
END
|
||||
@@ -0,0 +1,5 @@
|
||||
K 14
|
||||
svn:executable
|
||||
V 1
|
||||
*
|
||||
END
|
||||
@@ -0,0 +1,5 @@
|
||||
K 14
|
||||
svn:executable
|
||||
V 1
|
||||
*
|
||||
END
|
||||
@@ -0,0 +1,5 @@
|
||||
K 14
|
||||
svn:executable
|
||||
V 1
|
||||
*
|
||||
END
|
||||
@@ -0,0 +1,5 @@
|
||||
K 14
|
||||
svn:executable
|
||||
V 1
|
||||
*
|
||||
END
|
||||
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// ASIAuthenticationDialog.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 21/08/2009.
|
||||
// Copyright 2009 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
@class ASIHTTPRequest;
|
||||
|
||||
typedef enum _ASIAuthenticationType {
|
||||
ASIStandardAuthenticationType = 0,
|
||||
ASIProxyAuthenticationType = 1
|
||||
} ASIAuthenticationType;
|
||||
|
||||
@interface ASIAutorotatingViewController : UIViewController
|
||||
@end
|
||||
|
||||
@interface ASIAuthenticationDialog : ASIAutorotatingViewController <UIActionSheetDelegate, UITableViewDelegate, UITableViewDataSource> {
|
||||
ASIHTTPRequest *request;
|
||||
ASIAuthenticationType type;
|
||||
UITableView *tableView;
|
||||
UIViewController *presentingController;
|
||||
BOOL didEnableRotationNotifications;
|
||||
}
|
||||
+ (void)presentAuthenticationDialogForRequest:(ASIHTTPRequest *)request;
|
||||
+ (void)dismiss;
|
||||
|
||||
@property (retain) ASIHTTPRequest *request;
|
||||
@property (assign) ASIAuthenticationType type;
|
||||
@property (assign) BOOL didEnableRotationNotifications;
|
||||
@property (retain, nonatomic) UIViewController *presentingController;
|
||||
@end
|
||||
@@ -0,0 +1,493 @@
|
||||
//
|
||||
// ASIAuthenticationDialog.m
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 21/08/2009.
|
||||
// Copyright 2009 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ASIAuthenticationDialog.h"
|
||||
#import "ASIHTTPRequest.h"
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
|
||||
static ASIAuthenticationDialog *sharedDialog = nil;
|
||||
BOOL isDismissing = NO;
|
||||
static NSMutableArray *requestsNeedingAuthentication = nil;
|
||||
|
||||
static const NSUInteger kUsernameRow = 0;
|
||||
static const NSUInteger kUsernameSection = 0;
|
||||
static const NSUInteger kPasswordRow = 1;
|
||||
static const NSUInteger kPasswordSection = 0;
|
||||
static const NSUInteger kDomainRow = 0;
|
||||
static const NSUInteger kDomainSection = 1;
|
||||
|
||||
|
||||
@implementation ASIAutorotatingViewController
|
||||
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface ASIAuthenticationDialog ()
|
||||
- (void)showTitle;
|
||||
- (void)show;
|
||||
- (NSArray *)requestsRequiringTheseCredentials;
|
||||
- (void)presentNextDialog;
|
||||
- (void)keyboardWillShow:(NSNotification *)notification;
|
||||
- (void)orientationChanged:(NSNotification *)notification;
|
||||
- (void)cancelAuthenticationFromDialog:(id)sender;
|
||||
- (void)loginWithCredentialsFromDialog:(id)sender;
|
||||
@property (retain) UITableView *tableView;
|
||||
@end
|
||||
|
||||
@implementation ASIAuthenticationDialog
|
||||
|
||||
#pragma mark init / dealloc
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
if (self == [ASIAuthenticationDialog class]) {
|
||||
requestsNeedingAuthentication = [[NSMutableArray array] retain];
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)presentAuthenticationDialogForRequest:(ASIHTTPRequest *)theRequest
|
||||
{
|
||||
// No need for a lock here, this will always be called on the main thread
|
||||
if (!sharedDialog) {
|
||||
sharedDialog = [[self alloc] init];
|
||||
[sharedDialog setRequest:theRequest];
|
||||
if ([theRequest authenticationNeeded] == ASIProxyAuthenticationNeeded) {
|
||||
[sharedDialog setType:ASIProxyAuthenticationType];
|
||||
} else {
|
||||
[sharedDialog setType:ASIStandardAuthenticationType];
|
||||
}
|
||||
[sharedDialog show];
|
||||
} else {
|
||||
[requestsNeedingAuthentication addObject:theRequest];
|
||||
}
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if ((self = [self initWithNibName:nil bundle:nil])) {
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
|
||||
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2
|
||||
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
|
||||
#endif
|
||||
if (![UIDevice currentDevice].generatesDeviceOrientationNotifications) {
|
||||
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
|
||||
[self setDidEnableRotationNotifications:YES];
|
||||
}
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:nil];
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
if ([self didEnableRotationNotifications]) {
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil];
|
||||
}
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
|
||||
|
||||
[request release];
|
||||
[tableView release];
|
||||
[presentingController.view removeFromSuperview];
|
||||
[presentingController release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
#pragma mark keyboard notifications
|
||||
|
||||
- (void)keyboardWillShow:(NSNotification *)notification
|
||||
{
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2
|
||||
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
|
||||
#endif
|
||||
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_3_2
|
||||
NSValue *keyboardBoundsValue = [[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey];
|
||||
#else
|
||||
NSValue *keyboardBoundsValue = [[notification userInfo] objectForKey:UIKeyboardBoundsUserInfoKey];
|
||||
#endif
|
||||
CGRect keyboardBounds;
|
||||
[keyboardBoundsValue getValue:&keyboardBounds];
|
||||
UIEdgeInsets e = UIEdgeInsetsMake(0, 0, keyboardBounds.size.height, 0);
|
||||
[[self tableView] setScrollIndicatorInsets:e];
|
||||
[[self tableView] setContentInset:e];
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Manually handles orientation changes on iPhone
|
||||
- (void)orientationChanged:(NSNotification *)notification
|
||||
{
|
||||
[self showTitle];
|
||||
|
||||
UIInterfaceOrientation o = (UIInterfaceOrientation)[[UIApplication sharedApplication] statusBarOrientation];
|
||||
CGFloat angle = 0;
|
||||
switch (o) {
|
||||
case UIDeviceOrientationLandscapeLeft: angle = 90; break;
|
||||
case UIDeviceOrientationLandscapeRight: angle = -90; break;
|
||||
case UIDeviceOrientationPortraitUpsideDown: angle = 180; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
CGRect f = [[UIScreen mainScreen] applicationFrame];
|
||||
|
||||
// Swap the frame height and width if necessary
|
||||
if (UIDeviceOrientationIsLandscape(o)) {
|
||||
CGFloat t;
|
||||
t = f.size.width;
|
||||
f.size.width = f.size.height;
|
||||
f.size.height = t;
|
||||
}
|
||||
|
||||
CGAffineTransform previousTransform = self.view.layer.affineTransform;
|
||||
CGAffineTransform newTransform = CGAffineTransformMakeRotation((CGFloat)(angle * M_PI / 180.0));
|
||||
|
||||
// Reset the transform so we can set the size
|
||||
self.view.layer.affineTransform = CGAffineTransformIdentity;
|
||||
self.view.frame = (CGRect){ { 0, 0 }, f.size};
|
||||
|
||||
// Revert to the previous transform for correct animation
|
||||
self.view.layer.affineTransform = previousTransform;
|
||||
|
||||
[UIView beginAnimations:nil context:NULL];
|
||||
[UIView setAnimationDuration:0.3];
|
||||
|
||||
// Set the new transform
|
||||
self.view.layer.affineTransform = newTransform;
|
||||
|
||||
// Fix the view origin
|
||||
self.view.frame = (CGRect){ { f.origin.x, f.origin.y },self.view.frame.size};
|
||||
[UIView commitAnimations];
|
||||
}
|
||||
|
||||
#pragma mark utilities
|
||||
|
||||
- (UIViewController *)presentingController
|
||||
{
|
||||
if (!presentingController) {
|
||||
presentingController = [[ASIAutorotatingViewController alloc] initWithNibName:nil bundle:nil];
|
||||
|
||||
// Attach to the window, but don't interfere.
|
||||
UIWindow *window = [[[UIApplication sharedApplication] windows] objectAtIndex:0];
|
||||
[window addSubview:[presentingController view]];
|
||||
[[presentingController view] setFrame:CGRectZero];
|
||||
[[presentingController view] setUserInteractionEnabled:NO];
|
||||
}
|
||||
|
||||
return presentingController;
|
||||
}
|
||||
|
||||
- (UITextField *)textFieldInRow:(NSUInteger)row section:(NSUInteger)section
|
||||
{
|
||||
return [[[[[self tableView] cellForRowAtIndexPath:
|
||||
[NSIndexPath indexPathForRow:row inSection:section]]
|
||||
contentView] subviews] objectAtIndex:0];
|
||||
}
|
||||
|
||||
- (UITextField *)usernameField
|
||||
{
|
||||
return [self textFieldInRow:kUsernameRow section:kUsernameSection];
|
||||
}
|
||||
|
||||
- (UITextField *)passwordField
|
||||
{
|
||||
return [self textFieldInRow:kPasswordRow section:kPasswordSection];
|
||||
}
|
||||
|
||||
- (UITextField *)domainField
|
||||
{
|
||||
return [self textFieldInRow:kDomainRow section:kDomainSection];
|
||||
}
|
||||
|
||||
#pragma mark show / dismiss
|
||||
|
||||
+ (void)dismiss
|
||||
{
|
||||
if ([sharedDialog respondsToSelector:@selector(presentingViewController)])
|
||||
[[sharedDialog presentingViewController] dismissModalViewControllerAnimated:YES];
|
||||
else
|
||||
[[sharedDialog parentViewController] dismissModalViewControllerAnimated:YES];
|
||||
}
|
||||
|
||||
- (void)viewDidDisappear:(BOOL)animated
|
||||
{
|
||||
[self retain];
|
||||
[sharedDialog release];
|
||||
sharedDialog = nil;
|
||||
[self performSelector:@selector(presentNextDialog) withObject:nil afterDelay:0];
|
||||
[self release];
|
||||
}
|
||||
|
||||
- (void)dismiss
|
||||
{
|
||||
if (self == sharedDialog) {
|
||||
[[self class] dismiss];
|
||||
} else {
|
||||
if ([self respondsToSelector:@selector(presentingViewController)])
|
||||
[[self presentingViewController] dismissModalViewControllerAnimated:YES];
|
||||
else
|
||||
[[self parentViewController] dismissModalViewControllerAnimated:YES];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)showTitle
|
||||
{
|
||||
UINavigationBar *navigationBar = [[[self view] subviews] objectAtIndex:0];
|
||||
UINavigationItem *navItem = [[navigationBar items] objectAtIndex:0];
|
||||
if (UIInterfaceOrientationIsPortrait([[UIDevice currentDevice] orientation])) {
|
||||
// Setup the title
|
||||
if ([self type] == ASIProxyAuthenticationType) {
|
||||
[navItem setPrompt:@"Login to this secure proxy server."];
|
||||
} else {
|
||||
[navItem setPrompt:@"Login to this secure server."];
|
||||
}
|
||||
} else {
|
||||
[navItem setPrompt:nil];
|
||||
}
|
||||
[navigationBar sizeToFit];
|
||||
CGRect f = [[self view] bounds];
|
||||
f.origin.y = [navigationBar frame].size.height;
|
||||
f.size.height -= f.origin.y;
|
||||
[[self tableView] setFrame:f];
|
||||
}
|
||||
|
||||
- (void)show
|
||||
{
|
||||
// Remove all subviews
|
||||
UIView *v;
|
||||
while ((v = [[[self view] subviews] lastObject])) {
|
||||
[v removeFromSuperview];
|
||||
}
|
||||
|
||||
// Setup toolbar
|
||||
UINavigationBar *bar = [[[UINavigationBar alloc] init] autorelease];
|
||||
[bar setAutoresizingMask:UIViewAutoresizingFlexibleWidth];
|
||||
|
||||
UINavigationItem *navItem = [[[UINavigationItem alloc] init] autorelease];
|
||||
bar.items = [NSArray arrayWithObject:navItem];
|
||||
|
||||
[[self view] addSubview:bar];
|
||||
|
||||
[self showTitle];
|
||||
|
||||
// Setup toolbar buttons
|
||||
if ([self type] == ASIProxyAuthenticationType) {
|
||||
[navItem setTitle:[[self request] proxyHost]];
|
||||
} else {
|
||||
[navItem setTitle:[[[self request] url] host]];
|
||||
}
|
||||
|
||||
[navItem setLeftBarButtonItem:[[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancelAuthenticationFromDialog:)] autorelease]];
|
||||
[navItem setRightBarButtonItem:[[[UIBarButtonItem alloc] initWithTitle:@"Login" style:UIBarButtonItemStyleDone target:self action:@selector(loginWithCredentialsFromDialog:)] autorelease]];
|
||||
|
||||
// We show the login form in a table view, similar to Safari's authentication dialog
|
||||
[bar sizeToFit];
|
||||
CGRect f = [[self view] bounds];
|
||||
f.origin.y = [bar frame].size.height;
|
||||
f.size.height -= f.origin.y;
|
||||
|
||||
[self setTableView:[[[UITableView alloc] initWithFrame:f style:UITableViewStyleGrouped] autorelease]];
|
||||
[[self tableView] setDelegate:self];
|
||||
[[self tableView] setDataSource:self];
|
||||
[[self tableView] setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
|
||||
[[self view] addSubview:[self tableView]];
|
||||
|
||||
// Force reload the table content, and focus the first field to show the keyboard
|
||||
[[self tableView] reloadData];
|
||||
[[[[[self tableView] cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]].contentView subviews] objectAtIndex:0] becomeFirstResponder];
|
||||
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2
|
||||
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
|
||||
[self setModalPresentationStyle:UIModalPresentationFormSheet];
|
||||
}
|
||||
#endif
|
||||
|
||||
[[self presentingController] presentModalViewController:self animated:YES];
|
||||
}
|
||||
|
||||
#pragma mark button callbacks
|
||||
|
||||
- (void)cancelAuthenticationFromDialog:(id)sender
|
||||
{
|
||||
for (ASIHTTPRequest *theRequest in [self requestsRequiringTheseCredentials]) {
|
||||
[theRequest cancelAuthentication];
|
||||
[requestsNeedingAuthentication removeObject:theRequest];
|
||||
}
|
||||
[self dismiss];
|
||||
}
|
||||
|
||||
- (NSArray *)requestsRequiringTheseCredentials
|
||||
{
|
||||
NSMutableArray *requestsRequiringTheseCredentials = [NSMutableArray array];
|
||||
NSURL *requestURL = [[self request] url];
|
||||
for (ASIHTTPRequest *otherRequest in requestsNeedingAuthentication) {
|
||||
NSURL *theURL = [otherRequest url];
|
||||
if (([otherRequest authenticationNeeded] == [[self request] authenticationNeeded]) && [[theURL host] isEqualToString:[requestURL host]] && ([theURL port] == [requestURL port] || ([requestURL port] && [[theURL port] isEqualToNumber:[requestURL port]])) && [[theURL scheme] isEqualToString:[requestURL scheme]] && ((![otherRequest authenticationRealm] && ![[self request] authenticationRealm]) || ([otherRequest authenticationRealm] && [[self request] authenticationRealm] && [[[self request] authenticationRealm] isEqualToString:[otherRequest authenticationRealm]]))) {
|
||||
[requestsRequiringTheseCredentials addObject:otherRequest];
|
||||
}
|
||||
}
|
||||
[requestsRequiringTheseCredentials addObject:[self request]];
|
||||
return requestsRequiringTheseCredentials;
|
||||
}
|
||||
|
||||
- (void)presentNextDialog
|
||||
{
|
||||
if ([requestsNeedingAuthentication count]) {
|
||||
ASIHTTPRequest *nextRequest = [requestsNeedingAuthentication objectAtIndex:0];
|
||||
[requestsNeedingAuthentication removeObjectAtIndex:0];
|
||||
[[self class] presentAuthenticationDialogForRequest:nextRequest];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void)loginWithCredentialsFromDialog:(id)sender
|
||||
{
|
||||
for (ASIHTTPRequest *theRequest in [self requestsRequiringTheseCredentials]) {
|
||||
|
||||
NSString *username = [[self usernameField] text];
|
||||
NSString *password = [[self passwordField] text];
|
||||
|
||||
if (username == nil) { username = @""; }
|
||||
if (password == nil) { password = @""; }
|
||||
|
||||
if ([self type] == ASIProxyAuthenticationType) {
|
||||
[theRequest setProxyUsername:username];
|
||||
[theRequest setProxyPassword:password];
|
||||
} else {
|
||||
[theRequest setUsername:username];
|
||||
[theRequest setPassword:password];
|
||||
}
|
||||
|
||||
// Handle NTLM domains
|
||||
NSString *scheme = ([self type] == ASIStandardAuthenticationType) ? [[self request] authenticationScheme] : [[self request] proxyAuthenticationScheme];
|
||||
if ([scheme isEqualToString:(NSString *)kCFHTTPAuthenticationSchemeNTLM]) {
|
||||
NSString *domain = [[self domainField] text];
|
||||
if ([self type] == ASIProxyAuthenticationType) {
|
||||
[theRequest setProxyDomain:domain];
|
||||
} else {
|
||||
[theRequest setDomain:domain];
|
||||
}
|
||||
}
|
||||
|
||||
[theRequest retryUsingSuppliedCredentials];
|
||||
[requestsNeedingAuthentication removeObject:theRequest];
|
||||
}
|
||||
[self dismiss];
|
||||
}
|
||||
|
||||
#pragma mark table view data source
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)aTableView
|
||||
{
|
||||
NSString *scheme = ([self type] == ASIStandardAuthenticationType) ? [[self request] authenticationScheme] : [[self request] proxyAuthenticationScheme];
|
||||
if ([scheme isEqualToString:(NSString *)kCFHTTPAuthenticationSchemeNTLM]) {
|
||||
return 2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
- (CGFloat)tableView:(UITableView *)aTableView heightForFooterInSection:(NSInteger)section
|
||||
{
|
||||
if (section == [self numberOfSectionsInTableView:aTableView]-1) {
|
||||
return 30;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (CGFloat)tableView:(UITableView *)aTableView heightForHeaderInSection:(NSInteger)section
|
||||
{
|
||||
if (section == 0) {
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2
|
||||
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
|
||||
return 54;
|
||||
}
|
||||
#endif
|
||||
return 30;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
|
||||
{
|
||||
if (section == 0) {
|
||||
return [[self request] authenticationRealm];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_3_0
|
||||
UITableViewCell *cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil] autorelease];
|
||||
#else
|
||||
UITableViewCell *cell = [[[UITableViewCell alloc] initWithFrame:CGRectMake(0,0,0,0) reuseIdentifier:nil] autorelease];
|
||||
#endif
|
||||
|
||||
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
|
||||
|
||||
CGRect f = CGRectInset([cell bounds], 10, 10);
|
||||
UITextField *textField = [[[UITextField alloc] initWithFrame:f] autorelease];
|
||||
[textField setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
|
||||
[textField setAutocapitalizationType:UITextAutocapitalizationTypeNone];
|
||||
[textField setAutocorrectionType:UITextAutocorrectionTypeNo];
|
||||
|
||||
NSUInteger s = [indexPath section];
|
||||
NSUInteger r = [indexPath row];
|
||||
|
||||
if (s == kUsernameSection && r == kUsernameRow) {
|
||||
[textField setPlaceholder:@"User"];
|
||||
} else if (s == kPasswordSection && r == kPasswordRow) {
|
||||
[textField setPlaceholder:@"Password"];
|
||||
[textField setSecureTextEntry:YES];
|
||||
} else if (s == kDomainSection && r == kDomainRow) {
|
||||
[textField setPlaceholder:@"Domain"];
|
||||
}
|
||||
[cell.contentView addSubview:textField];
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)aTableView numberOfRowsInSection:(NSInteger)section
|
||||
{
|
||||
if (section == 0) {
|
||||
return 2;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)tableView:(UITableView *)aTableView titleForFooterInSection:(NSInteger)section
|
||||
{
|
||||
if (section == [self numberOfSectionsInTableView:aTableView]-1) {
|
||||
// If we're using Basic authentication and the connection is not using SSL, we'll show the plain text message
|
||||
if ([[[self request] authenticationScheme] isEqualToString:(NSString *)kCFHTTPAuthenticationSchemeBasic] && ![[[[self request] url] scheme] isEqualToString:@"https"]) {
|
||||
return @"Password will be sent in the clear.";
|
||||
// We are using Digest, NTLM, or any scheme over SSL
|
||||
} else {
|
||||
return @"Password will be sent securely.";
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@synthesize request;
|
||||
@synthesize type;
|
||||
@synthesize tableView;
|
||||
@synthesize didEnableRotationNotifications;
|
||||
@synthesize presentingController;
|
||||
@end
|
||||
103
msext/Class/Common/ASIHttpRequest/.svn/text-base/ASICacheDelegate.h.svn-base
Executable file
103
msext/Class/Common/ASIHttpRequest/.svn/text-base/ASICacheDelegate.h.svn-base
Executable file
@@ -0,0 +1,103 @@
|
||||
//
|
||||
// ASICacheDelegate.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 01/05/2010.
|
||||
// Copyright 2010 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
@class ASIHTTPRequest;
|
||||
|
||||
// Cache policies control the behaviour of a cache and how requests use the cache
|
||||
// When setting a cache policy, you can use a combination of these values as a bitmask
|
||||
// For example: [request setCachePolicy:ASIAskServerIfModifiedCachePolicy|ASIFallbackToCacheIfLoadFailsCachePolicy|ASIDoNotWriteToCacheCachePolicy];
|
||||
// Note that some of the behaviours below are mutally exclusive - you cannot combine ASIAskServerIfModifiedWhenStaleCachePolicy and ASIAskServerIfModifiedCachePolicy, for example.
|
||||
typedef enum _ASICachePolicy {
|
||||
|
||||
// The default cache policy. When you set a request to use this, it will use the cache's defaultCachePolicy
|
||||
// ASIDownloadCache's default cache policy is 'ASIAskServerIfModifiedWhenStaleCachePolicy'
|
||||
ASIUseDefaultCachePolicy = 0,
|
||||
|
||||
// Tell the request not to read from the cache
|
||||
ASIDoNotReadFromCacheCachePolicy = 1,
|
||||
|
||||
// The the request not to write to the cache
|
||||
ASIDoNotWriteToCacheCachePolicy = 2,
|
||||
|
||||
// Ask the server if there is an updated version of this resource (using a conditional GET) ONLY when the cached data is stale
|
||||
ASIAskServerIfModifiedWhenStaleCachePolicy = 4,
|
||||
|
||||
// Always ask the server if there is an updated version of this resource (using a conditional GET)
|
||||
ASIAskServerIfModifiedCachePolicy = 8,
|
||||
|
||||
// If cached data exists, use it even if it is stale. This means requests will not talk to the server unless the resource they are requesting is not in the cache
|
||||
ASIOnlyLoadIfNotCachedCachePolicy = 16,
|
||||
|
||||
// If cached data exists, use it even if it is stale. If cached data does not exist, stop (will not set an error on the request)
|
||||
ASIDontLoadCachePolicy = 32,
|
||||
|
||||
// Specifies that cached data may be used if the request fails. If cached data is used, the request will succeed without error. Usually used in combination with other options above.
|
||||
ASIFallbackToCacheIfLoadFailsCachePolicy = 64
|
||||
} ASICachePolicy;
|
||||
|
||||
// Cache storage policies control whether cached data persists between application launches (ASICachePermanentlyCacheStoragePolicy) or not (ASICacheForSessionDurationCacheStoragePolicy)
|
||||
// Calling [ASIHTTPRequest clearSession] will remove any data stored using ASICacheForSessionDurationCacheStoragePolicy
|
||||
typedef enum _ASICacheStoragePolicy {
|
||||
ASICacheForSessionDurationCacheStoragePolicy = 0,
|
||||
ASICachePermanentlyCacheStoragePolicy = 1
|
||||
} ASICacheStoragePolicy;
|
||||
|
||||
|
||||
@protocol ASICacheDelegate <NSObject>
|
||||
|
||||
@required
|
||||
|
||||
// Should return the cache policy that will be used when requests have their cache policy set to ASIUseDefaultCachePolicy
|
||||
- (ASICachePolicy)defaultCachePolicy;
|
||||
|
||||
// Returns the date a cached response should expire on. Pass a non-zero max age to specify a custom date.
|
||||
- (NSDate *)expiryDateForRequest:(ASIHTTPRequest *)request maxAge:(NSTimeInterval)maxAge;
|
||||
|
||||
// Updates cached response headers with a new expiry date. Pass a non-zero max age to specify a custom date.
|
||||
- (void)updateExpiryForRequest:(ASIHTTPRequest *)request maxAge:(NSTimeInterval)maxAge;
|
||||
|
||||
// Looks at the request's cache policy and any cached headers to determine if the cache data is still valid
|
||||
- (BOOL)canUseCachedDataForRequest:(ASIHTTPRequest *)request;
|
||||
|
||||
// Removes cached data for a particular request
|
||||
- (void)removeCachedDataForRequest:(ASIHTTPRequest *)request;
|
||||
|
||||
// Should return YES if the cache considers its cached response current for the request
|
||||
// Should return NO is the data is not cached, or (for example) if the cached headers state the request should have expired
|
||||
- (BOOL)isCachedDataCurrentForRequest:(ASIHTTPRequest *)request;
|
||||
|
||||
// Should store the response for the passed request in the cache
|
||||
// When a non-zero maxAge is passed, it should be used as the expiry time for the cached response
|
||||
- (void)storeResponseForRequest:(ASIHTTPRequest *)request maxAge:(NSTimeInterval)maxAge;
|
||||
|
||||
// Removes cached data for a particular url
|
||||
- (void)removeCachedDataForURL:(NSURL *)url;
|
||||
|
||||
// Should return an NSDictionary of cached headers for the passed URL, if it is stored in the cache
|
||||
- (NSDictionary *)cachedResponseHeadersForURL:(NSURL *)url;
|
||||
|
||||
// Should return the cached body of a response for the passed URL, if it is stored in the cache
|
||||
- (NSData *)cachedResponseDataForURL:(NSURL *)url;
|
||||
|
||||
// Returns a path to the cached response data, if it exists
|
||||
- (NSString *)pathToCachedResponseDataForURL:(NSURL *)url;
|
||||
|
||||
// Returns a path to the cached response headers, if they url
|
||||
- (NSString *)pathToCachedResponseHeadersForURL:(NSURL *)url;
|
||||
|
||||
// Returns the location to use to store cached response headers for a particular request
|
||||
- (NSString *)pathToStoreCachedResponseHeadersForRequest:(ASIHTTPRequest *)request;
|
||||
|
||||
// Returns the location to use to store a cached response body for a particular request
|
||||
- (NSString *)pathToStoreCachedResponseDataForRequest:(ASIHTTPRequest *)request;
|
||||
|
||||
// Clear cached data stored for the passed storage policy
|
||||
- (void)clearCachedResponsesForStoragePolicy:(ASICacheStoragePolicy)cachePolicy;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,42 @@
|
||||
//
|
||||
// ASIDataCompressor.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 17/08/2010.
|
||||
// Copyright 2010 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
// This is a helper class used by ASIHTTPRequest to handle deflating (compressing) data in memory and on disk
|
||||
// You may also find it helpful if you need to deflate data and files yourself - see the class methods below
|
||||
// Most of the zlib stuff is based on the sample code by Mark Adler available at http://zlib.net
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <zlib.h>
|
||||
|
||||
@interface ASIDataCompressor : NSObject {
|
||||
BOOL streamReady;
|
||||
z_stream zStream;
|
||||
}
|
||||
|
||||
// Convenience constructor will call setupStream for you
|
||||
+ (id)compressor;
|
||||
|
||||
// Compress the passed chunk of data
|
||||
// Passing YES for shouldFinish will finalize the deflated data - you must pass YES when you are on the last chunk of data
|
||||
- (NSData *)compressBytes:(Bytef *)bytes length:(NSUInteger)length error:(NSError **)err shouldFinish:(BOOL)shouldFinish;
|
||||
|
||||
// Convenience method - pass it some data, and you'll get deflated data back
|
||||
+ (NSData *)compressData:(NSData*)uncompressedData error:(NSError **)err;
|
||||
|
||||
// Convenience method - pass it a file containing the data to compress in sourcePath, and it will write deflated data to destinationPath
|
||||
+ (BOOL)compressDataFromFile:(NSString *)sourcePath toFile:(NSString *)destinationPath error:(NSError **)err;
|
||||
|
||||
// Sets up zlib to handle the inflating. You only need to call this yourself if you aren't using the convenience constructor 'compressor'
|
||||
- (NSError *)setupStream;
|
||||
|
||||
// Tells zlib to clean up. You need to call this if you need to cancel deflating part way through
|
||||
// If deflating finishes or fails, this method will be called automatically
|
||||
- (NSError *)closeStream;
|
||||
|
||||
@property (assign, readonly) BOOL streamReady;
|
||||
@end
|
||||
219
msext/Class/Common/ASIHttpRequest/.svn/text-base/ASIDataCompressor.m.svn-base
Executable file
219
msext/Class/Common/ASIHttpRequest/.svn/text-base/ASIDataCompressor.m.svn-base
Executable file
@@ -0,0 +1,219 @@
|
||||
//
|
||||
// ASIDataCompressor.m
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 17/08/2010.
|
||||
// Copyright 2010 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ASIDataCompressor.h"
|
||||
#import "ASIHTTPRequest.h"
|
||||
|
||||
#define DATA_CHUNK_SIZE 262144 // Deal with gzipped data in 256KB chunks
|
||||
#define COMPRESSION_AMOUNT Z_DEFAULT_COMPRESSION
|
||||
|
||||
@interface ASIDataCompressor ()
|
||||
+ (NSError *)deflateErrorWithCode:(int)code;
|
||||
@end
|
||||
|
||||
@implementation ASIDataCompressor
|
||||
|
||||
+ (id)compressor
|
||||
{
|
||||
ASIDataCompressor *compressor = [[[self alloc] init] autorelease];
|
||||
[compressor setupStream];
|
||||
return compressor;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
if (streamReady) {
|
||||
[self closeStream];
|
||||
}
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (NSError *)setupStream
|
||||
{
|
||||
if (streamReady) {
|
||||
return nil;
|
||||
}
|
||||
// Setup the inflate stream
|
||||
zStream.zalloc = Z_NULL;
|
||||
zStream.zfree = Z_NULL;
|
||||
zStream.opaque = Z_NULL;
|
||||
zStream.avail_in = 0;
|
||||
zStream.next_in = 0;
|
||||
int status = deflateInit2(&zStream, COMPRESSION_AMOUNT, Z_DEFLATED, (15+16), 8, Z_DEFAULT_STRATEGY);
|
||||
if (status != Z_OK) {
|
||||
return [[self class] deflateErrorWithCode:status];
|
||||
}
|
||||
streamReady = YES;
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSError *)closeStream
|
||||
{
|
||||
if (!streamReady) {
|
||||
return nil;
|
||||
}
|
||||
// Close the deflate stream
|
||||
streamReady = NO;
|
||||
int status = deflateEnd(&zStream);
|
||||
if (status != Z_OK) {
|
||||
return [[self class] deflateErrorWithCode:status];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSData *)compressBytes:(Bytef *)bytes length:(NSUInteger)length error:(NSError **)err shouldFinish:(BOOL)shouldFinish
|
||||
{
|
||||
if (length == 0) return nil;
|
||||
|
||||
NSUInteger halfLength = length/2;
|
||||
|
||||
// We'll take a guess that the compressed data will fit in half the size of the original (ie the max to compress at once is half DATA_CHUNK_SIZE), if not, we'll increase it below
|
||||
NSMutableData *outputData = [NSMutableData dataWithLength:length/2];
|
||||
|
||||
int status;
|
||||
|
||||
zStream.next_in = bytes;
|
||||
zStream.avail_in = (unsigned int)length;
|
||||
zStream.avail_out = 0;
|
||||
|
||||
NSInteger bytesProcessedAlready = zStream.total_out;
|
||||
while (zStream.avail_out == 0) {
|
||||
|
||||
if (zStream.total_out-bytesProcessedAlready >= [outputData length]) {
|
||||
[outputData increaseLengthBy:halfLength];
|
||||
}
|
||||
|
||||
zStream.next_out = (Bytef*)[outputData mutableBytes] + zStream.total_out-bytesProcessedAlready;
|
||||
zStream.avail_out = (unsigned int)([outputData length] - (zStream.total_out-bytesProcessedAlready));
|
||||
status = deflate(&zStream, shouldFinish ? Z_FINISH : Z_NO_FLUSH);
|
||||
|
||||
if (status == Z_STREAM_END) {
|
||||
break;
|
||||
} else if (status != Z_OK) {
|
||||
if (err) {
|
||||
*err = [[self class] deflateErrorWithCode:status];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
// Set real length
|
||||
[outputData setLength: zStream.total_out-bytesProcessedAlready];
|
||||
return outputData;
|
||||
}
|
||||
|
||||
|
||||
+ (NSData *)compressData:(NSData*)uncompressedData error:(NSError **)err
|
||||
{
|
||||
NSError *theError = nil;
|
||||
NSData *outputData = [[ASIDataCompressor compressor] compressBytes:(Bytef *)[uncompressedData bytes] length:[uncompressedData length] error:&theError shouldFinish:YES];
|
||||
if (theError) {
|
||||
if (err) {
|
||||
*err = theError;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
return outputData;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+ (BOOL)compressDataFromFile:(NSString *)sourcePath toFile:(NSString *)destinationPath error:(NSError **)err
|
||||
{
|
||||
NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease];
|
||||
|
||||
// Create an empty file at the destination path
|
||||
if (![fileManager createFileAtPath:destinationPath contents:[NSData data] attributes:nil]) {
|
||||
if (err) {
|
||||
*err = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Compression of %@ failed because we were to create a file at %@",sourcePath,destinationPath],NSLocalizedDescriptionKey,nil]];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Ensure the source file exists
|
||||
if (![fileManager fileExistsAtPath:sourcePath]) {
|
||||
if (err) {
|
||||
*err = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Compression of %@ failed the file does not exist",sourcePath],NSLocalizedDescriptionKey,nil]];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
UInt8 inputData[DATA_CHUNK_SIZE];
|
||||
NSData *outputData;
|
||||
NSInteger readLength;
|
||||
NSError *theError = nil;
|
||||
|
||||
ASIDataCompressor *compressor = [ASIDataCompressor compressor];
|
||||
|
||||
NSInputStream *inputStream = [NSInputStream inputStreamWithFileAtPath:sourcePath];
|
||||
[inputStream open];
|
||||
NSOutputStream *outputStream = [NSOutputStream outputStreamToFileAtPath:destinationPath append:NO];
|
||||
[outputStream open];
|
||||
|
||||
while ([compressor streamReady]) {
|
||||
|
||||
// Read some data from the file
|
||||
readLength = [inputStream read:inputData maxLength:DATA_CHUNK_SIZE];
|
||||
|
||||
// Make sure nothing went wrong
|
||||
if ([inputStream streamStatus] == NSStreamEventErrorOccurred) {
|
||||
if (err) {
|
||||
*err = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Compression of %@ failed because we were unable to read from the source data file",sourcePath],NSLocalizedDescriptionKey,[inputStream streamError],NSUnderlyingErrorKey,nil]];
|
||||
}
|
||||
[compressor closeStream];
|
||||
return NO;
|
||||
}
|
||||
// Have we reached the end of the input data?
|
||||
if (!readLength) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Attempt to deflate the chunk of data
|
||||
outputData = [compressor compressBytes:inputData length:readLength error:&theError shouldFinish:readLength < DATA_CHUNK_SIZE ];
|
||||
if (theError) {
|
||||
if (err) {
|
||||
*err = theError;
|
||||
}
|
||||
[compressor closeStream];
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Write the deflated data out to the destination file
|
||||
[outputStream write:(const uint8_t *)[outputData bytes] maxLength:[outputData length]];
|
||||
|
||||
// Make sure nothing went wrong
|
||||
if ([inputStream streamStatus] == NSStreamEventErrorOccurred) {
|
||||
if (err) {
|
||||
*err = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Compression of %@ failed because we were unable to write to the destination data file at %@",sourcePath,destinationPath],NSLocalizedDescriptionKey,[outputStream streamError],NSUnderlyingErrorKey,nil]];
|
||||
}
|
||||
[compressor closeStream];
|
||||
return NO;
|
||||
}
|
||||
|
||||
}
|
||||
[inputStream close];
|
||||
[outputStream close];
|
||||
|
||||
NSError *error = [compressor closeStream];
|
||||
if (error) {
|
||||
if (err) {
|
||||
*err = error;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
+ (NSError *)deflateErrorWithCode:(int)code
|
||||
{
|
||||
return [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Compression of data failed with code %hi",code],NSLocalizedDescriptionKey,nil]];
|
||||
}
|
||||
|
||||
@synthesize streamReady;
|
||||
@end
|
||||
@@ -0,0 +1,41 @@
|
||||
//
|
||||
// ASIDataDecompressor.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 17/08/2010.
|
||||
// Copyright 2010 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
// This is a helper class used by ASIHTTPRequest to handle inflating (decompressing) data in memory and on disk
|
||||
// You may also find it helpful if you need to inflate data and files yourself - see the class methods below
|
||||
// Most of the zlib stuff is based on the sample code by Mark Adler available at http://zlib.net
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <zlib.h>
|
||||
|
||||
@interface ASIDataDecompressor : NSObject {
|
||||
BOOL streamReady;
|
||||
z_stream zStream;
|
||||
}
|
||||
|
||||
// Convenience constructor will call setupStream for you
|
||||
+ (id)decompressor;
|
||||
|
||||
// Uncompress the passed chunk of data
|
||||
- (NSData *)uncompressBytes:(Bytef *)bytes length:(NSUInteger)length error:(NSError **)err;
|
||||
|
||||
// Convenience method - pass it some deflated data, and you'll get inflated data back
|
||||
+ (NSData *)uncompressData:(NSData*)compressedData error:(NSError **)err;
|
||||
|
||||
// Convenience method - pass it a file containing deflated data in sourcePath, and it will write inflated data to destinationPath
|
||||
+ (BOOL)uncompressDataFromFile:(NSString *)sourcePath toFile:(NSString *)destinationPath error:(NSError **)err;
|
||||
|
||||
// Sets up zlib to handle the inflating. You only need to call this yourself if you aren't using the convenience constructor 'decompressor'
|
||||
- (NSError *)setupStream;
|
||||
|
||||
// Tells zlib to clean up. You need to call this if you need to cancel inflating part way through
|
||||
// If inflating finishes or fails, this method will be called automatically
|
||||
- (NSError *)closeStream;
|
||||
|
||||
@property (assign, readonly) BOOL streamReady;
|
||||
@end
|
||||
218
msext/Class/Common/ASIHttpRequest/.svn/text-base/ASIDataDecompressor.m.svn-base
Executable file
218
msext/Class/Common/ASIHttpRequest/.svn/text-base/ASIDataDecompressor.m.svn-base
Executable file
@@ -0,0 +1,218 @@
|
||||
//
|
||||
// ASIDataDecompressor.m
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 17/08/2010.
|
||||
// Copyright 2010 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ASIDataDecompressor.h"
|
||||
#import "ASIHTTPRequest.h"
|
||||
|
||||
#define DATA_CHUNK_SIZE 262144 // Deal with gzipped data in 256KB chunks
|
||||
|
||||
@interface ASIDataDecompressor ()
|
||||
+ (NSError *)inflateErrorWithCode:(int)code;
|
||||
@end;
|
||||
|
||||
@implementation ASIDataDecompressor
|
||||
|
||||
+ (id)decompressor
|
||||
{
|
||||
ASIDataDecompressor *decompressor = [[[self alloc] init] autorelease];
|
||||
[decompressor setupStream];
|
||||
return decompressor;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
if (streamReady) {
|
||||
[self closeStream];
|
||||
}
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (NSError *)setupStream
|
||||
{
|
||||
if (streamReady) {
|
||||
return nil;
|
||||
}
|
||||
// Setup the inflate stream
|
||||
zStream.zalloc = Z_NULL;
|
||||
zStream.zfree = Z_NULL;
|
||||
zStream.opaque = Z_NULL;
|
||||
zStream.avail_in = 0;
|
||||
zStream.next_in = 0;
|
||||
int status = inflateInit2(&zStream, (15+32));
|
||||
if (status != Z_OK) {
|
||||
return [[self class] inflateErrorWithCode:status];
|
||||
}
|
||||
streamReady = YES;
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSError *)closeStream
|
||||
{
|
||||
if (!streamReady) {
|
||||
return nil;
|
||||
}
|
||||
// Close the inflate stream
|
||||
streamReady = NO;
|
||||
int status = inflateEnd(&zStream);
|
||||
if (status != Z_OK) {
|
||||
return [[self class] inflateErrorWithCode:status];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSData *)uncompressBytes:(Bytef *)bytes length:(NSUInteger)length error:(NSError **)err
|
||||
{
|
||||
if (length == 0) return nil;
|
||||
|
||||
NSUInteger halfLength = length/2;
|
||||
NSMutableData *outputData = [NSMutableData dataWithLength:length+halfLength];
|
||||
|
||||
int status;
|
||||
|
||||
zStream.next_in = bytes;
|
||||
zStream.avail_in = (unsigned int)length;
|
||||
zStream.avail_out = 0;
|
||||
|
||||
NSInteger bytesProcessedAlready = zStream.total_out;
|
||||
while (zStream.avail_in != 0) {
|
||||
|
||||
if (zStream.total_out-bytesProcessedAlready >= [outputData length]) {
|
||||
[outputData increaseLengthBy:halfLength];
|
||||
}
|
||||
|
||||
zStream.next_out = (Bytef*)[outputData mutableBytes] + zStream.total_out-bytesProcessedAlready;
|
||||
zStream.avail_out = (unsigned int)([outputData length] - (zStream.total_out-bytesProcessedAlready));
|
||||
|
||||
status = inflate(&zStream, Z_NO_FLUSH);
|
||||
|
||||
if (status == Z_STREAM_END) {
|
||||
break;
|
||||
} else if (status != Z_OK) {
|
||||
if (err) {
|
||||
*err = [[self class] inflateErrorWithCode:status];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
// Set real length
|
||||
[outputData setLength: zStream.total_out-bytesProcessedAlready];
|
||||
return outputData;
|
||||
}
|
||||
|
||||
|
||||
+ (NSData *)uncompressData:(NSData*)compressedData error:(NSError **)err
|
||||
{
|
||||
NSError *theError = nil;
|
||||
NSData *outputData = [[ASIDataDecompressor decompressor] uncompressBytes:(Bytef *)[compressedData bytes] length:[compressedData length] error:&theError];
|
||||
if (theError) {
|
||||
if (err) {
|
||||
*err = theError;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
return outputData;
|
||||
}
|
||||
|
||||
+ (BOOL)uncompressDataFromFile:(NSString *)sourcePath toFile:(NSString *)destinationPath error:(NSError **)err
|
||||
{
|
||||
NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease];
|
||||
|
||||
// Create an empty file at the destination path
|
||||
if (![fileManager createFileAtPath:destinationPath contents:[NSData data] attributes:nil]) {
|
||||
if (err) {
|
||||
*err = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Decompression of %@ failed because we were to create a file at %@",sourcePath,destinationPath],NSLocalizedDescriptionKey,nil]];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Ensure the source file exists
|
||||
if (![fileManager fileExistsAtPath:sourcePath]) {
|
||||
if (err) {
|
||||
*err = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Decompression of %@ failed the file does not exist",sourcePath],NSLocalizedDescriptionKey,nil]];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
UInt8 inputData[DATA_CHUNK_SIZE];
|
||||
NSData *outputData;
|
||||
NSInteger readLength;
|
||||
NSError *theError = nil;
|
||||
|
||||
|
||||
ASIDataDecompressor *decompressor = [ASIDataDecompressor decompressor];
|
||||
|
||||
NSInputStream *inputStream = [NSInputStream inputStreamWithFileAtPath:sourcePath];
|
||||
[inputStream open];
|
||||
NSOutputStream *outputStream = [NSOutputStream outputStreamToFileAtPath:destinationPath append:NO];
|
||||
[outputStream open];
|
||||
|
||||
while ([decompressor streamReady]) {
|
||||
|
||||
// Read some data from the file
|
||||
readLength = [inputStream read:inputData maxLength:DATA_CHUNK_SIZE];
|
||||
|
||||
// Make sure nothing went wrong
|
||||
if ([inputStream streamStatus] == NSStreamEventErrorOccurred) {
|
||||
if (err) {
|
||||
*err = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Decompression of %@ failed because we were unable to read from the source data file",sourcePath],NSLocalizedDescriptionKey,[inputStream streamError],NSUnderlyingErrorKey,nil]];
|
||||
}
|
||||
[decompressor closeStream];
|
||||
return NO;
|
||||
}
|
||||
// Have we reached the end of the input data?
|
||||
if (!readLength) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Attempt to inflate the chunk of data
|
||||
outputData = [decompressor uncompressBytes:inputData length:readLength error:&theError];
|
||||
if (theError) {
|
||||
if (err) {
|
||||
*err = theError;
|
||||
}
|
||||
[decompressor closeStream];
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Write the inflated data out to the destination file
|
||||
[outputStream write:(Bytef*)[outputData bytes] maxLength:[outputData length]];
|
||||
|
||||
// Make sure nothing went wrong
|
||||
if ([inputStream streamStatus] == NSStreamEventErrorOccurred) {
|
||||
if (err) {
|
||||
*err = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Decompression of %@ failed because we were unable to write to the destination data file at %@",sourcePath,destinationPath],NSLocalizedDescriptionKey,[outputStream streamError],NSUnderlyingErrorKey,nil]];
|
||||
}
|
||||
[decompressor closeStream];
|
||||
return NO;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[inputStream close];
|
||||
[outputStream close];
|
||||
|
||||
NSError *error = [decompressor closeStream];
|
||||
if (error) {
|
||||
if (err) {
|
||||
*err = error;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
+ (NSError *)inflateErrorWithCode:(int)code
|
||||
{
|
||||
return [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Decompression of data failed with code %hi",code],NSLocalizedDescriptionKey,nil]];
|
||||
}
|
||||
|
||||
@synthesize streamReady;
|
||||
@end
|
||||
46
msext/Class/Common/ASIHttpRequest/.svn/text-base/ASIDownloadCache.h.svn-base
Executable file
46
msext/Class/Common/ASIHttpRequest/.svn/text-base/ASIDownloadCache.h.svn-base
Executable file
@@ -0,0 +1,46 @@
|
||||
//
|
||||
// ASIDownloadCache.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 01/05/2010.
|
||||
// Copyright 2010 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "ASICacheDelegate.h"
|
||||
|
||||
@interface ASIDownloadCache : NSObject <ASICacheDelegate> {
|
||||
|
||||
// The default cache policy for this cache
|
||||
// Requests that store data in the cache will use this cache policy if their cache policy is set to ASIUseDefaultCachePolicy
|
||||
// Defaults to ASIAskServerIfModifiedWhenStaleCachePolicy
|
||||
ASICachePolicy defaultCachePolicy;
|
||||
|
||||
// The directory in which cached data will be stored
|
||||
// Defaults to a directory called 'ASIHTTPRequestCache' in the temporary directory
|
||||
NSString *storagePath;
|
||||
|
||||
// Mediates access to the cache
|
||||
NSRecursiveLock *accessLock;
|
||||
|
||||
// When YES, the cache will look for cache-control / pragma: no-cache headers, and won't reuse store responses if it finds them
|
||||
BOOL shouldRespectCacheControlHeaders;
|
||||
}
|
||||
|
||||
// Returns a static instance of an ASIDownloadCache
|
||||
// In most circumstances, it will make sense to use this as a global cache, rather than creating your own cache
|
||||
// To make ASIHTTPRequests use it automatically, use [ASIHTTPRequest setDefaultCache:[ASIDownloadCache sharedCache]];
|
||||
+ (id)sharedCache;
|
||||
|
||||
// A helper function that determines if the server has requested data should not be cached by looking at the request's response headers
|
||||
+ (BOOL)serverAllowsResponseCachingForRequest:(ASIHTTPRequest *)request;
|
||||
|
||||
// A list of file extensions that we know won't be readable by a webview when accessed locally
|
||||
// If we're asking for a path to cache a particular url and it has one of these extensions, we change it to '.html'
|
||||
+ (NSArray *)fileExtensionsToHandleAsHTML;
|
||||
|
||||
@property (assign, nonatomic) ASICachePolicy defaultCachePolicy;
|
||||
@property (retain, nonatomic) NSString *storagePath;
|
||||
@property (retain) NSRecursiveLock *accessLock;
|
||||
@property (assign) BOOL shouldRespectCacheControlHeaders;
|
||||
@end
|
||||
514
msext/Class/Common/ASIHttpRequest/.svn/text-base/ASIDownloadCache.m.svn-base
Executable file
514
msext/Class/Common/ASIHttpRequest/.svn/text-base/ASIDownloadCache.m.svn-base
Executable file
@@ -0,0 +1,514 @@
|
||||
//
|
||||
// ASIDownloadCache.m
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 01/05/2010.
|
||||
// Copyright 2010 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ASIDownloadCache.h"
|
||||
#import "ASIHTTPRequest.h"
|
||||
#import <CommonCrypto/CommonHMAC.h>
|
||||
|
||||
static ASIDownloadCache *sharedCache = nil;
|
||||
|
||||
static NSString *sessionCacheFolder = @"SessionStore";
|
||||
static NSString *permanentCacheFolder = @"PermanentStore";
|
||||
static NSArray *fileExtensionsToHandleAsHTML = nil;
|
||||
|
||||
@interface ASIDownloadCache ()
|
||||
+ (NSString *)keyForURL:(NSURL *)url;
|
||||
- (NSString *)pathToFile:(NSString *)file;
|
||||
@end
|
||||
|
||||
@implementation ASIDownloadCache
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
if (self == [ASIDownloadCache class]) {
|
||||
// Obviously this is not an exhaustive list, but hopefully these are the most commonly used and this will 'just work' for the widest range of people
|
||||
// I imagine many web developers probably use url rewriting anyway
|
||||
fileExtensionsToHandleAsHTML = [[NSArray alloc] initWithObjects:@"asp",@"aspx",@"jsp",@"php",@"rb",@"py",@"pl",@"cgi", nil];
|
||||
}
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
[self setShouldRespectCacheControlHeaders:YES];
|
||||
[self setDefaultCachePolicy:ASIUseDefaultCachePolicy];
|
||||
[self setAccessLock:[[[NSRecursiveLock alloc] init] autorelease]];
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (id)sharedCache
|
||||
{
|
||||
if (!sharedCache) {
|
||||
@synchronized(self) {
|
||||
if (!sharedCache) {
|
||||
sharedCache = [[self alloc] init];
|
||||
[sharedCache setStoragePath:[[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:@"ASIHTTPRequestCache"]];
|
||||
}
|
||||
}
|
||||
}
|
||||
return sharedCache;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[storagePath release];
|
||||
[accessLock release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (NSString *)storagePath
|
||||
{
|
||||
[[self accessLock] lock];
|
||||
NSString *p = [[storagePath retain] autorelease];
|
||||
[[self accessLock] unlock];
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
- (void)setStoragePath:(NSString *)path
|
||||
{
|
||||
[[self accessLock] lock];
|
||||
[self clearCachedResponsesForStoragePolicy:ASICacheForSessionDurationCacheStoragePolicy];
|
||||
[storagePath release];
|
||||
storagePath = [path retain];
|
||||
|
||||
NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease];
|
||||
|
||||
BOOL isDirectory = NO;
|
||||
NSArray *directories = [NSArray arrayWithObjects:path,[path stringByAppendingPathComponent:sessionCacheFolder],[path stringByAppendingPathComponent:permanentCacheFolder],nil];
|
||||
for (NSString *directory in directories) {
|
||||
BOOL exists = [fileManager fileExistsAtPath:directory isDirectory:&isDirectory];
|
||||
if (exists && !isDirectory) {
|
||||
[[self accessLock] unlock];
|
||||
[NSException raise:@"FileExistsAtCachePath" format:@"Cannot create a directory for the cache at '%@', because a file already exists",directory];
|
||||
} else if (!exists) {
|
||||
[fileManager createDirectoryAtPath:directory withIntermediateDirectories:NO attributes:nil error:nil];
|
||||
if (![fileManager fileExistsAtPath:directory]) {
|
||||
[[self accessLock] unlock];
|
||||
[NSException raise:@"FailedToCreateCacheDirectory" format:@"Failed to create a directory for the cache at '%@'",directory];
|
||||
}
|
||||
}
|
||||
}
|
||||
[self clearCachedResponsesForStoragePolicy:ASICacheForSessionDurationCacheStoragePolicy];
|
||||
[[self accessLock] unlock];
|
||||
}
|
||||
|
||||
- (void)updateExpiryForRequest:(ASIHTTPRequest *)request maxAge:(NSTimeInterval)maxAge
|
||||
{
|
||||
NSString *headerPath = [self pathToStoreCachedResponseHeadersForRequest:request];
|
||||
NSMutableDictionary *cachedHeaders = [NSMutableDictionary dictionaryWithContentsOfFile:headerPath];
|
||||
if (!cachedHeaders) {
|
||||
return;
|
||||
}
|
||||
NSDate *expires = [self expiryDateForRequest:request maxAge:maxAge];
|
||||
if (!expires) {
|
||||
return;
|
||||
}
|
||||
[cachedHeaders setObject:[NSNumber numberWithDouble:[expires timeIntervalSince1970]] forKey:@"X-ASIHTTPRequest-Expires"];
|
||||
[cachedHeaders writeToFile:headerPath atomically:NO];
|
||||
}
|
||||
|
||||
- (NSDate *)expiryDateForRequest:(ASIHTTPRequest *)request maxAge:(NSTimeInterval)maxAge
|
||||
{
|
||||
return [ASIHTTPRequest expiryDateForRequest:request maxAge:maxAge];
|
||||
}
|
||||
|
||||
- (void)storeResponseForRequest:(ASIHTTPRequest *)request maxAge:(NSTimeInterval)maxAge
|
||||
{
|
||||
[[self accessLock] lock];
|
||||
|
||||
if ([request error] || ![request responseHeaders] || ([request cachePolicy] & ASIDoNotWriteToCacheCachePolicy)) {
|
||||
[[self accessLock] unlock];
|
||||
return;
|
||||
}
|
||||
|
||||
// We only cache 200/OK or redirect reponses (redirect responses are cached so the cache works better with no internet connection)
|
||||
int responseCode = [request responseStatusCode];
|
||||
if (responseCode != 200 && responseCode != 301 && responseCode != 302 && responseCode != 303 && responseCode != 307) {
|
||||
[[self accessLock] unlock];
|
||||
return;
|
||||
}
|
||||
|
||||
if ([self shouldRespectCacheControlHeaders] && ![[self class] serverAllowsResponseCachingForRequest:request]) {
|
||||
[[self accessLock] unlock];
|
||||
return;
|
||||
}
|
||||
|
||||
NSString *headerPath = [self pathToStoreCachedResponseHeadersForRequest:request];
|
||||
NSString *dataPath = [self pathToStoreCachedResponseDataForRequest:request];
|
||||
|
||||
NSMutableDictionary *responseHeaders = [NSMutableDictionary dictionaryWithDictionary:[request responseHeaders]];
|
||||
if ([request isResponseCompressed]) {
|
||||
[responseHeaders removeObjectForKey:@"Content-Encoding"];
|
||||
}
|
||||
|
||||
// Create a special 'X-ASIHTTPRequest-Expires' header
|
||||
// This is what we use for deciding if cached data is current, rather than parsing the expires / max-age headers individually each time
|
||||
// We store this as a timestamp to make reading it easier as NSDateFormatter is quite expensive
|
||||
|
||||
NSDate *expires = [self expiryDateForRequest:request maxAge:maxAge];
|
||||
if (expires) {
|
||||
[responseHeaders setObject:[NSNumber numberWithDouble:[expires timeIntervalSince1970]] forKey:@"X-ASIHTTPRequest-Expires"];
|
||||
}
|
||||
|
||||
// Store the response code in a custom header so we can reuse it later
|
||||
|
||||
// We'll change 304/Not Modified to 200/OK because this is likely to be us updating the cached headers with a conditional GET
|
||||
int statusCode = [request responseStatusCode];
|
||||
if (statusCode == 304) {
|
||||
statusCode = 200;
|
||||
}
|
||||
[responseHeaders setObject:[NSNumber numberWithInt:statusCode] forKey:@"X-ASIHTTPRequest-Response-Status-Code"];
|
||||
|
||||
[responseHeaders writeToFile:headerPath atomically:NO];
|
||||
|
||||
if ([request responseData]) {
|
||||
[[request responseData] writeToFile:dataPath atomically:NO];
|
||||
} else if ([request downloadDestinationPath] && ![[request downloadDestinationPath] isEqualToString:dataPath]) {
|
||||
NSError *error = nil;
|
||||
NSFileManager* manager = [[NSFileManager alloc] init];
|
||||
if ([manager fileExistsAtPath:dataPath]) {
|
||||
[manager removeItemAtPath:dataPath error:&error];
|
||||
}
|
||||
[manager copyItemAtPath:[request downloadDestinationPath] toPath:dataPath error:&error];
|
||||
[manager release];
|
||||
}
|
||||
[[self accessLock] unlock];
|
||||
}
|
||||
|
||||
- (NSDictionary *)cachedResponseHeadersForURL:(NSURL *)url
|
||||
{
|
||||
NSString *path = [self pathToCachedResponseHeadersForURL:url];
|
||||
if (path) {
|
||||
return [NSDictionary dictionaryWithContentsOfFile:path];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSData *)cachedResponseDataForURL:(NSURL *)url
|
||||
{
|
||||
NSString *path = [self pathToCachedResponseDataForURL:url];
|
||||
if (path) {
|
||||
return [NSData dataWithContentsOfFile:path];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSString *)pathToCachedResponseDataForURL:(NSURL *)url
|
||||
{
|
||||
// Grab the file extension, if there is one. We do this so we can save the cached response with the same file extension - this is important if you want to display locally cached data in a web view
|
||||
NSString *extension = [[url path] pathExtension];
|
||||
|
||||
// If the url doesn't have an extension, we'll add one so a webview can read it when locally cached
|
||||
// If the url has the extension of a common web scripting language, we'll change the extension on the cached path to html for the same reason
|
||||
if (![extension length] || [[[self class] fileExtensionsToHandleAsHTML] containsObject:[extension lowercaseString]]) {
|
||||
extension = @"html";
|
||||
}
|
||||
return [self pathToFile:[[[self class] keyForURL:url] stringByAppendingPathExtension:extension]];
|
||||
}
|
||||
|
||||
+ (NSArray *)fileExtensionsToHandleAsHTML
|
||||
{
|
||||
return fileExtensionsToHandleAsHTML;
|
||||
}
|
||||
|
||||
|
||||
- (NSString *)pathToCachedResponseHeadersForURL:(NSURL *)url
|
||||
{
|
||||
return [self pathToFile:[[[self class] keyForURL:url] stringByAppendingPathExtension:@"cachedheaders"]];
|
||||
}
|
||||
|
||||
- (NSString *)pathToFile:(NSString *)file
|
||||
{
|
||||
[[self accessLock] lock];
|
||||
if (![self storagePath]) {
|
||||
[[self accessLock] unlock];
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease];
|
||||
|
||||
// Look in the session store
|
||||
NSString *dataPath = [[[self storagePath] stringByAppendingPathComponent:sessionCacheFolder] stringByAppendingPathComponent:file];
|
||||
if ([fileManager fileExistsAtPath:dataPath]) {
|
||||
[[self accessLock] unlock];
|
||||
return dataPath;
|
||||
}
|
||||
// Look in the permanent store
|
||||
dataPath = [[[self storagePath] stringByAppendingPathComponent:permanentCacheFolder] stringByAppendingPathComponent:file];
|
||||
if ([fileManager fileExistsAtPath:dataPath]) {
|
||||
[[self accessLock] unlock];
|
||||
return dataPath;
|
||||
}
|
||||
[[self accessLock] unlock];
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
- (NSString *)pathToStoreCachedResponseDataForRequest:(ASIHTTPRequest *)request
|
||||
{
|
||||
[[self accessLock] lock];
|
||||
if (![self storagePath]) {
|
||||
[[self accessLock] unlock];
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSString *path = [[self storagePath] stringByAppendingPathComponent:([request cacheStoragePolicy] == ASICacheForSessionDurationCacheStoragePolicy ? sessionCacheFolder : permanentCacheFolder)];
|
||||
|
||||
// Grab the file extension, if there is one. We do this so we can save the cached response with the same file extension - this is important if you want to display locally cached data in a web view
|
||||
NSString *extension = [[[request url] path] pathExtension];
|
||||
|
||||
// If the url doesn't have an extension, we'll add one so a webview can read it when locally cached
|
||||
// If the url has the extension of a common web scripting language, we'll change the extension on the cached path to html for the same reason
|
||||
if (![extension length] || [[[self class] fileExtensionsToHandleAsHTML] containsObject:[extension lowercaseString]]) {
|
||||
extension = @"html";
|
||||
}
|
||||
path = [path stringByAppendingPathComponent:[[[self class] keyForURL:[request url]] stringByAppendingPathExtension:extension]];
|
||||
[[self accessLock] unlock];
|
||||
return path;
|
||||
}
|
||||
|
||||
- (NSString *)pathToStoreCachedResponseHeadersForRequest:(ASIHTTPRequest *)request
|
||||
{
|
||||
[[self accessLock] lock];
|
||||
if (![self storagePath]) {
|
||||
[[self accessLock] unlock];
|
||||
return nil;
|
||||
}
|
||||
NSString *path = [[self storagePath] stringByAppendingPathComponent:([request cacheStoragePolicy] == ASICacheForSessionDurationCacheStoragePolicy ? sessionCacheFolder : permanentCacheFolder)];
|
||||
path = [path stringByAppendingPathComponent:[[[self class] keyForURL:[request url]] stringByAppendingPathExtension:@"cachedheaders"]];
|
||||
[[self accessLock] unlock];
|
||||
return path;
|
||||
}
|
||||
|
||||
- (void)removeCachedDataForURL:(NSURL *)url
|
||||
{
|
||||
[[self accessLock] lock];
|
||||
if (![self storagePath]) {
|
||||
[[self accessLock] unlock];
|
||||
return;
|
||||
}
|
||||
NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease];
|
||||
|
||||
NSString *path = [self pathToCachedResponseHeadersForURL:url];
|
||||
if (path) {
|
||||
[fileManager removeItemAtPath:path error:NULL];
|
||||
}
|
||||
|
||||
path = [self pathToCachedResponseDataForURL:url];
|
||||
if (path) {
|
||||
[fileManager removeItemAtPath:path error:NULL];
|
||||
}
|
||||
[[self accessLock] unlock];
|
||||
}
|
||||
|
||||
- (void)removeCachedDataForRequest:(ASIHTTPRequest *)request
|
||||
{
|
||||
[self removeCachedDataForURL:[request url]];
|
||||
}
|
||||
|
||||
- (BOOL)isCachedDataCurrentForRequest:(ASIHTTPRequest *)request
|
||||
{
|
||||
[[self accessLock] lock];
|
||||
if (![self storagePath]) {
|
||||
[[self accessLock] unlock];
|
||||
return NO;
|
||||
}
|
||||
NSDictionary *cachedHeaders = [self cachedResponseHeadersForURL:[request url]];
|
||||
if (!cachedHeaders) {
|
||||
[[self accessLock] unlock];
|
||||
return NO;
|
||||
}
|
||||
NSString *dataPath = [self pathToCachedResponseDataForURL:[request url]];
|
||||
if (!dataPath) {
|
||||
[[self accessLock] unlock];
|
||||
return NO;
|
||||
}
|
||||
|
||||
// New content is not different
|
||||
if ([request responseStatusCode] == 304) {
|
||||
[[self accessLock] unlock];
|
||||
return YES;
|
||||
}
|
||||
|
||||
// If we already have response headers for this request, check to see if the new content is different
|
||||
// We check [request complete] so that we don't end up comparing response headers from a redirection with these
|
||||
if ([request responseHeaders] && [request complete]) {
|
||||
|
||||
// If the Etag or Last-Modified date are different from the one we have, we'll have to fetch this resource again
|
||||
NSArray *headersToCompare = [NSArray arrayWithObjects:@"Etag",@"Last-Modified",nil];
|
||||
for (NSString *header in headersToCompare) {
|
||||
if (![[[request responseHeaders] objectForKey:header] isEqualToString:[cachedHeaders objectForKey:header]]) {
|
||||
[[self accessLock] unlock];
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ([self shouldRespectCacheControlHeaders]) {
|
||||
|
||||
// Look for X-ASIHTTPRequest-Expires header to see if the content is out of date
|
||||
NSNumber *expires = [cachedHeaders objectForKey:@"X-ASIHTTPRequest-Expires"];
|
||||
if (expires) {
|
||||
if ([[NSDate dateWithTimeIntervalSince1970:[expires doubleValue]] timeIntervalSinceNow] >= 0) {
|
||||
[[self accessLock] unlock];
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
// No explicit expiration time sent by the server
|
||||
[[self accessLock] unlock];
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
||||
[[self accessLock] unlock];
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (ASICachePolicy)defaultCachePolicy
|
||||
{
|
||||
[[self accessLock] lock];
|
||||
ASICachePolicy cp = defaultCachePolicy;
|
||||
[[self accessLock] unlock];
|
||||
return cp;
|
||||
}
|
||||
|
||||
|
||||
- (void)setDefaultCachePolicy:(ASICachePolicy)cachePolicy
|
||||
{
|
||||
[[self accessLock] lock];
|
||||
if (!cachePolicy) {
|
||||
defaultCachePolicy = ASIAskServerIfModifiedWhenStaleCachePolicy;
|
||||
} else {
|
||||
defaultCachePolicy = cachePolicy;
|
||||
}
|
||||
[[self accessLock] unlock];
|
||||
}
|
||||
|
||||
- (void)clearCachedResponsesForStoragePolicy:(ASICacheStoragePolicy)storagePolicy
|
||||
{
|
||||
[[self accessLock] lock];
|
||||
if (![self storagePath]) {
|
||||
[[self accessLock] unlock];
|
||||
return;
|
||||
}
|
||||
NSString *path = [[self storagePath] stringByAppendingPathComponent:(storagePolicy == ASICacheForSessionDurationCacheStoragePolicy ? sessionCacheFolder : permanentCacheFolder)];
|
||||
|
||||
NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease];
|
||||
|
||||
BOOL isDirectory = NO;
|
||||
BOOL exists = [fileManager fileExistsAtPath:path isDirectory:&isDirectory];
|
||||
if (!exists || !isDirectory) {
|
||||
[[self accessLock] unlock];
|
||||
return;
|
||||
}
|
||||
NSError *error = nil;
|
||||
NSArray *cacheFiles = [fileManager contentsOfDirectoryAtPath:path error:&error];
|
||||
if (error) {
|
||||
[[self accessLock] unlock];
|
||||
[NSException raise:@"FailedToTraverseCacheDirectory" format:@"Listing cache directory failed at path '%@'",path];
|
||||
}
|
||||
for (NSString *file in cacheFiles) {
|
||||
[fileManager removeItemAtPath:[path stringByAppendingPathComponent:file] error:&error];
|
||||
if (error) {
|
||||
[[self accessLock] unlock];
|
||||
[NSException raise:@"FailedToRemoveCacheFile" format:@"Failed to remove cached data at path '%@'",path];
|
||||
}
|
||||
}
|
||||
[[self accessLock] unlock];
|
||||
}
|
||||
|
||||
+ (BOOL)serverAllowsResponseCachingForRequest:(ASIHTTPRequest *)request
|
||||
{
|
||||
NSString *cacheControl = [[[request responseHeaders] objectForKey:@"Cache-Control"] lowercaseString];
|
||||
if (cacheControl) {
|
||||
if ([cacheControl isEqualToString:@"no-cache"] || [cacheControl isEqualToString:@"no-store"]) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
NSString *pragma = [[[request responseHeaders] objectForKey:@"Pragma"] lowercaseString];
|
||||
if (pragma) {
|
||||
if ([pragma isEqualToString:@"no-cache"]) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
+ (NSString *)keyForURL:(NSURL *)url
|
||||
{
|
||||
NSString *urlString = [url absoluteString];
|
||||
if ([urlString length] == 0) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
// Strip trailing slashes so http://allseeing-i.com/ASIHTTPRequest/ is cached the same as http://allseeing-i.com/ASIHTTPRequest
|
||||
if ([[urlString substringFromIndex:[urlString length]-1] isEqualToString:@"/"]) {
|
||||
urlString = [urlString substringToIndex:[urlString length]-1];
|
||||
}
|
||||
|
||||
// Borrowed from: http://stackoverflow.com/questions/652300/using-md5-hash-on-a-string-in-cocoa
|
||||
const char *cStr = [urlString UTF8String];
|
||||
unsigned char result[16];
|
||||
CC_MD5(cStr, (CC_LONG)strlen(cStr), result);
|
||||
return [NSString stringWithFormat:@"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",result[0], result[1], result[2], result[3], result[4], result[5], result[6], result[7],result[8], result[9], result[10], result[11],result[12], result[13], result[14], result[15]];
|
||||
}
|
||||
|
||||
- (BOOL)canUseCachedDataForRequest:(ASIHTTPRequest *)request
|
||||
{
|
||||
// Ensure the request is allowed to read from the cache
|
||||
if ([request cachePolicy] & ASIDoNotReadFromCacheCachePolicy) {
|
||||
return NO;
|
||||
|
||||
// If we don't want to load the request whatever happens, always pretend we have cached data even if we don't
|
||||
} else if ([request cachePolicy] & ASIDontLoadCachePolicy) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
NSDictionary *headers = [self cachedResponseHeadersForURL:[request url]];
|
||||
if (!headers) {
|
||||
return NO;
|
||||
}
|
||||
NSString *dataPath = [self pathToCachedResponseDataForURL:[request url]];
|
||||
if (!dataPath) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
// If we get here, we have cached data
|
||||
|
||||
// If we have cached data, we can use it
|
||||
if ([request cachePolicy] & ASIOnlyLoadIfNotCachedCachePolicy) {
|
||||
return YES;
|
||||
|
||||
// If we want to fallback to the cache after an error
|
||||
} else if ([request complete] && [request cachePolicy] & ASIFallbackToCacheIfLoadFailsCachePolicy) {
|
||||
return YES;
|
||||
|
||||
// If we have cached data that is current, we can use it
|
||||
} else if ([request cachePolicy] & ASIAskServerIfModifiedWhenStaleCachePolicy) {
|
||||
if ([self isCachedDataCurrentForRequest:request]) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
// If we've got headers from a conditional GET and the cached data is still current, we can use it
|
||||
} else if ([request cachePolicy] & ASIAskServerIfModifiedCachePolicy) {
|
||||
if (![request responseHeaders]) {
|
||||
return NO;
|
||||
} else if ([self isCachedDataCurrentForRequest:request]) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
@synthesize storagePath;
|
||||
@synthesize defaultCachePolicy;
|
||||
@synthesize accessLock;
|
||||
@synthesize shouldRespectCacheControlHeaders;
|
||||
@end
|
||||
@@ -0,0 +1,76 @@
|
||||
//
|
||||
// ASIFormDataRequest.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 07/11/2008.
|
||||
// Copyright 2008-2009 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "ASIHTTPRequest.h"
|
||||
#import "ASIHTTPRequestConfig.h"
|
||||
|
||||
typedef enum _ASIPostFormat {
|
||||
ASIMultipartFormDataPostFormat = 0,
|
||||
ASIURLEncodedPostFormat = 1
|
||||
|
||||
} ASIPostFormat;
|
||||
|
||||
@interface ASIFormDataRequest : ASIHTTPRequest <NSCopying> {
|
||||
|
||||
// Parameters that will be POSTed to the url
|
||||
NSMutableArray *postData;
|
||||
|
||||
// Files that will be POSTed to the url
|
||||
NSMutableArray *fileData;
|
||||
|
||||
ASIPostFormat postFormat;
|
||||
|
||||
NSStringEncoding stringEncoding;
|
||||
|
||||
#if DEBUG_FORM_DATA_REQUEST
|
||||
// Will store a string version of the request body that will be printed to the console when ASIHTTPREQUEST_DEBUG is set in GCC_PREPROCESSOR_DEFINITIONS
|
||||
NSString *debugBodyString;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#pragma mark utilities
|
||||
- (NSString*)encodeURL:(NSString *)string;
|
||||
|
||||
#pragma mark setup request
|
||||
|
||||
// Add a POST variable to the request
|
||||
- (void)addPostValue:(id <NSObject>)value forKey:(NSString *)key;
|
||||
|
||||
// Set a POST variable for this request, clearing any others with the same key
|
||||
- (void)setPostValue:(id <NSObject>)value forKey:(NSString *)key;
|
||||
|
||||
// Add the contents of a local file to the request
|
||||
- (void)addFile:(NSString *)filePath forKey:(NSString *)key;
|
||||
|
||||
// Same as above, but you can specify the content-type and file name
|
||||
- (void)addFile:(NSString *)filePath withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key;
|
||||
|
||||
// Add the contents of a local file to the request, clearing any others with the same key
|
||||
- (void)setFile:(NSString *)filePath forKey:(NSString *)key;
|
||||
|
||||
// Same as above, but you can specify the content-type and file name
|
||||
- (void)setFile:(NSString *)filePath withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key;
|
||||
|
||||
// Add the contents of an NSData object to the request
|
||||
- (void)addData:(NSData *)data forKey:(NSString *)key;
|
||||
|
||||
// Same as above, but you can specify the content-type and file name
|
||||
- (void)addData:(id)data withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key;
|
||||
|
||||
// Add the contents of an NSData object to the request, clearing any others with the same key
|
||||
- (void)setData:(NSData *)data forKey:(NSString *)key;
|
||||
|
||||
// Same as above, but you can specify the content-type and file name
|
||||
- (void)setData:(id)data withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key;
|
||||
|
||||
|
||||
@property (assign) ASIPostFormat postFormat;
|
||||
@property (assign) NSStringEncoding stringEncoding;
|
||||
@end
|
||||
362
msext/Class/Common/ASIHttpRequest/.svn/text-base/ASIFormDataRequest.m.svn-base
Executable file
362
msext/Class/Common/ASIHttpRequest/.svn/text-base/ASIFormDataRequest.m.svn-base
Executable file
@@ -0,0 +1,362 @@
|
||||
//
|
||||
// ASIFormDataRequest.m
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 07/11/2008.
|
||||
// Copyright 2008-2009 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ASIFormDataRequest.h"
|
||||
|
||||
|
||||
// Private stuff
|
||||
@interface ASIFormDataRequest ()
|
||||
- (void)buildMultipartFormDataPostBody;
|
||||
- (void)buildURLEncodedPostBody;
|
||||
- (void)appendPostString:(NSString *)string;
|
||||
|
||||
@property (retain) NSMutableArray *postData;
|
||||
@property (retain) NSMutableArray *fileData;
|
||||
|
||||
#if DEBUG_FORM_DATA_REQUEST
|
||||
- (void)addToDebugBody:(NSString *)string;
|
||||
@property (retain, nonatomic) NSString *debugBodyString;
|
||||
#endif
|
||||
|
||||
@end
|
||||
|
||||
@implementation ASIFormDataRequest
|
||||
|
||||
#pragma mark utilities
|
||||
- (NSString*)encodeURL:(NSString *)string
|
||||
{
|
||||
NSString *newString = [NSMakeCollectable(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)string, NULL, CFSTR(":/?#[]@!$ &'()*+,;=\"<>%{}|\\^~`"), CFStringConvertNSStringEncodingToEncoding([self stringEncoding]))) autorelease];
|
||||
if (newString) {
|
||||
return newString;
|
||||
}
|
||||
return @"";
|
||||
}
|
||||
|
||||
#pragma mark init / dealloc
|
||||
|
||||
+ (id)requestWithURL:(NSURL *)newURL
|
||||
{
|
||||
return [[[self alloc] initWithURL:newURL] autorelease];
|
||||
}
|
||||
|
||||
- (id)initWithURL:(NSURL *)newURL
|
||||
{
|
||||
self = [super initWithURL:newURL];
|
||||
[self setPostFormat:ASIURLEncodedPostFormat];
|
||||
[self setStringEncoding:NSUTF8StringEncoding];
|
||||
[self setRequestMethod:@"POST"];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
#if DEBUG_FORM_DATA_REQUEST
|
||||
[debugBodyString release];
|
||||
#endif
|
||||
|
||||
[postData release];
|
||||
[fileData release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
#pragma mark setup request
|
||||
|
||||
- (void)addPostValue:(id <NSObject>)value forKey:(NSString *)key
|
||||
{
|
||||
if (!key) {
|
||||
return;
|
||||
}
|
||||
if (![self postData]) {
|
||||
[self setPostData:[NSMutableArray array]];
|
||||
}
|
||||
NSMutableDictionary *keyValuePair = [NSMutableDictionary dictionaryWithCapacity:2];
|
||||
[keyValuePair setValue:key forKey:@"key"];
|
||||
[keyValuePair setValue:[value description] forKey:@"value"];
|
||||
[[self postData] addObject:keyValuePair];
|
||||
}
|
||||
|
||||
- (void)setPostValue:(id <NSObject>)value forKey:(NSString *)key
|
||||
{
|
||||
// Remove any existing value
|
||||
NSUInteger i;
|
||||
for (i=0; i<[[self postData] count]; i++) {
|
||||
NSDictionary *val = [[self postData] objectAtIndex:i];
|
||||
if ([[val objectForKey:@"key"] isEqualToString:key]) {
|
||||
[[self postData] removeObjectAtIndex:i];
|
||||
i--;
|
||||
}
|
||||
}
|
||||
[self addPostValue:value forKey:key];
|
||||
}
|
||||
|
||||
|
||||
- (void)addFile:(NSString *)filePath forKey:(NSString *)key
|
||||
{
|
||||
[self addFile:filePath withFileName:nil andContentType:nil forKey:key];
|
||||
}
|
||||
|
||||
- (void)addFile:(NSString *)filePath withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key
|
||||
{
|
||||
BOOL isDirectory = NO;
|
||||
BOOL fileExists = [[[[NSFileManager alloc] init] autorelease] fileExistsAtPath:filePath isDirectory:&isDirectory];
|
||||
if (!fileExists || isDirectory) {
|
||||
[self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIInternalErrorWhileBuildingRequestType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"No file exists at %@",filePath],NSLocalizedDescriptionKey,nil]]];
|
||||
}
|
||||
|
||||
// If the caller didn't specify a custom file name, we'll use the file name of the file we were passed
|
||||
if (!fileName) {
|
||||
fileName = [filePath lastPathComponent];
|
||||
}
|
||||
|
||||
// If we were given the path to a file, and the user didn't specify a mime type, we can detect it from the file extension
|
||||
if (!contentType) {
|
||||
contentType = [ASIHTTPRequest mimeTypeForFileAtPath:filePath];
|
||||
}
|
||||
[self addData:filePath withFileName:fileName andContentType:contentType forKey:key];
|
||||
}
|
||||
|
||||
- (void)setFile:(NSString *)filePath forKey:(NSString *)key
|
||||
{
|
||||
[self setFile:filePath withFileName:nil andContentType:nil forKey:key];
|
||||
}
|
||||
|
||||
- (void)setFile:(id)data withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key
|
||||
{
|
||||
// Remove any existing value
|
||||
NSUInteger i;
|
||||
for (i=0; i<[[self fileData] count]; i++) {
|
||||
NSDictionary *val = [[self fileData] objectAtIndex:i];
|
||||
if ([[val objectForKey:@"key"] isEqualToString:key]) {
|
||||
[[self fileData] removeObjectAtIndex:i];
|
||||
i--;
|
||||
}
|
||||
}
|
||||
[self addFile:data withFileName:fileName andContentType:contentType forKey:key];
|
||||
}
|
||||
|
||||
- (void)addData:(NSData *)data forKey:(NSString *)key
|
||||
{
|
||||
[self addData:data withFileName:@"file" andContentType:nil forKey:key];
|
||||
}
|
||||
|
||||
- (void)addData:(id)data withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key
|
||||
{
|
||||
if (![self fileData]) {
|
||||
[self setFileData:[NSMutableArray array]];
|
||||
}
|
||||
if (!contentType) {
|
||||
contentType = @"application/octet-stream";
|
||||
}
|
||||
|
||||
NSMutableDictionary *fileInfo = [NSMutableDictionary dictionaryWithCapacity:4];
|
||||
[fileInfo setValue:key forKey:@"key"];
|
||||
[fileInfo setValue:fileName forKey:@"fileName"];
|
||||
[fileInfo setValue:contentType forKey:@"contentType"];
|
||||
[fileInfo setValue:data forKey:@"data"];
|
||||
|
||||
[[self fileData] addObject:fileInfo];
|
||||
}
|
||||
|
||||
- (void)setData:(NSData *)data forKey:(NSString *)key
|
||||
{
|
||||
[self setData:data withFileName:@"file" andContentType:nil forKey:key];
|
||||
}
|
||||
|
||||
- (void)setData:(id)data withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key
|
||||
{
|
||||
// Remove any existing value
|
||||
NSUInteger i;
|
||||
for (i=0; i<[[self fileData] count]; i++) {
|
||||
NSDictionary *val = [[self fileData] objectAtIndex:i];
|
||||
if ([[val objectForKey:@"key"] isEqualToString:key]) {
|
||||
[[self fileData] removeObjectAtIndex:i];
|
||||
i--;
|
||||
}
|
||||
}
|
||||
[self addData:data withFileName:fileName andContentType:contentType forKey:key];
|
||||
}
|
||||
|
||||
- (void)buildPostBody
|
||||
{
|
||||
if ([self haveBuiltPostBody]) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if DEBUG_FORM_DATA_REQUEST
|
||||
[self setDebugBodyString:@""];
|
||||
#endif
|
||||
|
||||
if (![self postData] && ![self fileData]) {
|
||||
[super buildPostBody];
|
||||
return;
|
||||
}
|
||||
if ([[self fileData] count] > 0) {
|
||||
[self setShouldStreamPostDataFromDisk:YES];
|
||||
}
|
||||
|
||||
if ([self postFormat] == ASIURLEncodedPostFormat) {
|
||||
[self buildURLEncodedPostBody];
|
||||
} else {
|
||||
[self buildMultipartFormDataPostBody];
|
||||
}
|
||||
|
||||
[super buildPostBody];
|
||||
|
||||
#if DEBUG_FORM_DATA_REQUEST
|
||||
ASI_DEBUG_LOG(@"%@",[self debugBodyString]);
|
||||
[self setDebugBodyString:nil];
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
- (void)buildMultipartFormDataPostBody
|
||||
{
|
||||
#if DEBUG_FORM_DATA_REQUEST
|
||||
[self addToDebugBody:@"\r\n==== Building a multipart/form-data body ====\r\n"];
|
||||
#endif
|
||||
|
||||
NSString *charset = (NSString *)CFStringConvertEncodingToIANACharSetName(CFStringConvertNSStringEncodingToEncoding([self stringEncoding]));
|
||||
|
||||
// We don't bother to check if post data contains the boundary, since it's pretty unlikely that it does.
|
||||
CFUUIDRef uuid = CFUUIDCreate(nil);
|
||||
NSString *uuidString = [(NSString*)CFUUIDCreateString(nil, uuid) autorelease];
|
||||
CFRelease(uuid);
|
||||
NSString *stringBoundary = [NSString stringWithFormat:@"0xKhTmLbOuNdArY-%@",uuidString];
|
||||
|
||||
[self addRequestHeader:@"Content-Type" value:[NSString stringWithFormat:@"multipart/form-data; charset=%@; boundary=%@", charset, stringBoundary]];
|
||||
|
||||
[self appendPostString:[NSString stringWithFormat:@"--%@\r\n",stringBoundary]];
|
||||
|
||||
// Adds post data
|
||||
NSString *endItemBoundary = [NSString stringWithFormat:@"\r\n--%@\r\n",stringBoundary];
|
||||
NSUInteger i=0;
|
||||
for (NSDictionary *val in [self postData]) {
|
||||
[self appendPostString:[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n",[val objectForKey:@"key"]]];
|
||||
[self appendPostString:[val objectForKey:@"value"]];
|
||||
i++;
|
||||
if (i != [[self postData] count] || [[self fileData] count] > 0) { //Only add the boundary if this is not the last item in the post body
|
||||
[self appendPostString:endItemBoundary];
|
||||
}
|
||||
}
|
||||
|
||||
// Adds files to upload
|
||||
i=0;
|
||||
for (NSDictionary *val in [self fileData]) {
|
||||
|
||||
[self appendPostString:[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", [val objectForKey:@"key"], [val objectForKey:@"fileName"]]];
|
||||
[self appendPostString:[NSString stringWithFormat:@"Content-Type: %@\r\n\r\n", [val objectForKey:@"contentType"]]];
|
||||
|
||||
id data = [val objectForKey:@"data"];
|
||||
if ([data isKindOfClass:[NSString class]]) {
|
||||
[self appendPostDataFromFile:data];
|
||||
} else {
|
||||
[self appendPostData:data];
|
||||
}
|
||||
i++;
|
||||
// Only add the boundary if this is not the last item in the post body
|
||||
if (i != [[self fileData] count]) {
|
||||
[self appendPostString:endItemBoundary];
|
||||
}
|
||||
}
|
||||
|
||||
[self appendPostString:[NSString stringWithFormat:@"\r\n--%@--\r\n",stringBoundary]];
|
||||
|
||||
#if DEBUG_FORM_DATA_REQUEST
|
||||
[self addToDebugBody:@"==== End of multipart/form-data body ====\r\n"];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)buildURLEncodedPostBody
|
||||
{
|
||||
|
||||
// We can't post binary data using application/x-www-form-urlencoded
|
||||
if ([[self fileData] count] > 0) {
|
||||
[self setPostFormat:ASIMultipartFormDataPostFormat];
|
||||
[self buildMultipartFormDataPostBody];
|
||||
return;
|
||||
}
|
||||
|
||||
#if DEBUG_FORM_DATA_REQUEST
|
||||
[self addToDebugBody:@"\r\n==== Building an application/x-www-form-urlencoded body ====\r\n"];
|
||||
#endif
|
||||
|
||||
|
||||
NSString *charset = (NSString *)CFStringConvertEncodingToIANACharSetName(CFStringConvertNSStringEncodingToEncoding([self stringEncoding]));
|
||||
|
||||
[self addRequestHeader:@"Content-Type" value:[NSString stringWithFormat:@"application/x-www-form-urlencoded; charset=%@",charset]];
|
||||
|
||||
|
||||
NSUInteger i=0;
|
||||
NSUInteger count = [[self postData] count]-1;
|
||||
for (NSDictionary *val in [self postData]) {
|
||||
NSString *data = [NSString stringWithFormat:@"%@=%@%@", [self encodeURL:[val objectForKey:@"key"]], [self encodeURL:[val objectForKey:@"value"]],(i<count ? @"&" : @"")];
|
||||
[self appendPostString:data];
|
||||
i++;
|
||||
}
|
||||
#if DEBUG_FORM_DATA_REQUEST
|
||||
[self addToDebugBody:@"\r\n==== End of application/x-www-form-urlencoded body ====\r\n"];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)appendPostString:(NSString *)string
|
||||
{
|
||||
#if DEBUG_FORM_DATA_REQUEST
|
||||
[self addToDebugBody:string];
|
||||
#endif
|
||||
[super appendPostData:[string dataUsingEncoding:[self stringEncoding]]];
|
||||
}
|
||||
|
||||
#if DEBUG_FORM_DATA_REQUEST
|
||||
- (void)appendPostData:(NSData *)data
|
||||
{
|
||||
[self addToDebugBody:[NSString stringWithFormat:@"[%lu bytes of data]",(unsigned long)[data length]]];
|
||||
[super appendPostData:data];
|
||||
}
|
||||
|
||||
- (void)appendPostDataFromFile:(NSString *)file
|
||||
{
|
||||
NSError *err = nil;
|
||||
unsigned long long fileSize = [[[[[[NSFileManager alloc] init] autorelease] attributesOfItemAtPath:file error:&err] objectForKey:NSFileSize] unsignedLongLongValue];
|
||||
if (err) {
|
||||
[self addToDebugBody:[NSString stringWithFormat:@"[Error: Failed to obtain the size of the file at '%@']",file]];
|
||||
} else {
|
||||
[self addToDebugBody:[NSString stringWithFormat:@"[%llu bytes of data from file '%@']",fileSize,file]];
|
||||
}
|
||||
|
||||
[super appendPostDataFromFile:file];
|
||||
}
|
||||
|
||||
- (void)addToDebugBody:(NSString *)string
|
||||
{
|
||||
if (string) {
|
||||
[self setDebugBodyString:[[self debugBodyString] stringByAppendingString:string]];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#pragma mark NSCopying
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
ASIFormDataRequest *newRequest = [super copyWithZone:zone];
|
||||
[newRequest setPostData:[[[self postData] mutableCopyWithZone:zone] autorelease]];
|
||||
[newRequest setFileData:[[[self fileData] mutableCopyWithZone:zone] autorelease]];
|
||||
[newRequest setPostFormat:[self postFormat]];
|
||||
[newRequest setStringEncoding:[self stringEncoding]];
|
||||
[newRequest setRequestMethod:[self requestMethod]];
|
||||
return newRequest;
|
||||
}
|
||||
|
||||
@synthesize postData;
|
||||
@synthesize fileData;
|
||||
@synthesize postFormat;
|
||||
@synthesize stringEncoding;
|
||||
#if DEBUG_FORM_DATA_REQUEST
|
||||
@synthesize debugBodyString;
|
||||
#endif
|
||||
@end
|
||||
1004
msext/Class/Common/ASIHttpRequest/.svn/text-base/ASIHTTPRequest.h.svn-base
Executable file
1004
msext/Class/Common/ASIHttpRequest/.svn/text-base/ASIHTTPRequest.h.svn-base
Executable file
File diff suppressed because it is too large
Load Diff
5125
msext/Class/Common/ASIHttpRequest/.svn/text-base/ASIHTTPRequest.m.svn-base
Executable file
5125
msext/Class/Common/ASIHttpRequest/.svn/text-base/ASIHTTPRequest.m.svn-base
Executable file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,43 @@
|
||||
//
|
||||
// ASIHTTPRequestConfig.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 14/12/2009.
|
||||
// Copyright 2009 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
// ======
|
||||
// Debug output configuration options
|
||||
// ======
|
||||
|
||||
// If defined will use the specified function for debug logging
|
||||
// Otherwise use NSLog
|
||||
#ifndef ASI_DEBUG_LOG
|
||||
#define ASI_DEBUG_LOG NSLog
|
||||
#endif
|
||||
|
||||
// When set to 1 ASIHTTPRequests will print information about what a request is doing
|
||||
#ifndef DEBUG_REQUEST_STATUS
|
||||
#define DEBUG_REQUEST_STATUS 0
|
||||
#endif
|
||||
|
||||
// When set to 1, ASIFormDataRequests will print information about the request body to the console
|
||||
#ifndef DEBUG_FORM_DATA_REQUEST
|
||||
#define DEBUG_FORM_DATA_REQUEST 0
|
||||
#endif
|
||||
|
||||
// When set to 1, ASIHTTPRequests will print information about bandwidth throttling to the console
|
||||
#ifndef DEBUG_THROTTLING
|
||||
#define DEBUG_THROTTLING 0
|
||||
#endif
|
||||
|
||||
// When set to 1, ASIHTTPRequests will print information about persistent connections to the console
|
||||
#ifndef DEBUG_PERSISTENT_CONNECTIONS
|
||||
#define DEBUG_PERSISTENT_CONNECTIONS 0
|
||||
#endif
|
||||
|
||||
// When set to 1, ASIHTTPRequests will print information about HTTP authentication (Basic, Digest or NTLM) to the console
|
||||
#ifndef DEBUG_HTTP_AUTHENTICATION
|
||||
#define DEBUG_HTTP_AUTHENTICATION 0
|
||||
#endif
|
||||
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// ASIHTTPRequestDelegate.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 13/04/2010.
|
||||
// Copyright 2010 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
@class ASIHTTPRequest;
|
||||
|
||||
@protocol ASIHTTPRequestDelegate <NSObject>
|
||||
|
||||
@optional
|
||||
|
||||
// These are the default delegate methods for request status
|
||||
// You can use different ones by setting didStartSelector / didFinishSelector / didFailSelector
|
||||
- (void)requestStarted:(ASIHTTPRequest *)request;
|
||||
- (void)request:(ASIHTTPRequest *)request didReceiveResponseHeaders:(NSDictionary *)responseHeaders;
|
||||
- (void)request:(ASIHTTPRequest *)request willRedirectToURL:(NSURL *)newURL;
|
||||
- (void)requestFinished:(ASIHTTPRequest *)request;
|
||||
- (void)requestFailed:(ASIHTTPRequest *)request;
|
||||
- (void)requestRedirected:(ASIHTTPRequest *)request;
|
||||
|
||||
// When a delegate implements this method, it is expected to process all incoming data itself
|
||||
// This means that responseData / responseString / downloadDestinationPath etc are ignored
|
||||
// You can have the request call a different method by setting didReceiveDataSelector
|
||||
- (void)request:(ASIHTTPRequest *)request didReceiveData:(NSData *)data;
|
||||
|
||||
// If a delegate implements one of these, it will be asked to supply credentials when none are available
|
||||
// The delegate can then either restart the request ([request retryUsingSuppliedCredentials]) once credentials have been set
|
||||
// or cancel it ([request cancelAuthentication])
|
||||
- (void)authenticationNeededForRequest:(ASIHTTPRequest *)request;
|
||||
- (void)proxyAuthenticationNeededForRequest:(ASIHTTPRequest *)request;
|
||||
|
||||
@end
|
||||
26
msext/Class/Common/ASIHttpRequest/.svn/text-base/ASIInputStream.h.svn-base
Executable file
26
msext/Class/Common/ASIHttpRequest/.svn/text-base/ASIInputStream.h.svn-base
Executable file
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// ASIInputStream.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 10/08/2009.
|
||||
// Copyright 2009 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class ASIHTTPRequest;
|
||||
|
||||
// This is a wrapper for NSInputStream that pretends to be an NSInputStream itself
|
||||
// Subclassing NSInputStream seems to be tricky, and may involve overriding undocumented methods, so we'll cheat instead.
|
||||
// It is used by ASIHTTPRequest whenever we have a request body, and handles measuring and throttling the bandwidth used for uploading
|
||||
|
||||
@interface ASIInputStream : NSObject {
|
||||
NSInputStream *stream;
|
||||
ASIHTTPRequest *request;
|
||||
}
|
||||
+ (id)inputStreamWithFileAtPath:(NSString *)path request:(ASIHTTPRequest *)request;
|
||||
+ (id)inputStreamWithData:(NSData *)data request:(ASIHTTPRequest *)request;
|
||||
|
||||
@property (retain, nonatomic) NSInputStream *stream;
|
||||
@property (assign, nonatomic) ASIHTTPRequest *request;
|
||||
@end
|
||||
138
msext/Class/Common/ASIHttpRequest/.svn/text-base/ASIInputStream.m.svn-base
Executable file
138
msext/Class/Common/ASIHttpRequest/.svn/text-base/ASIInputStream.m.svn-base
Executable file
@@ -0,0 +1,138 @@
|
||||
//
|
||||
// ASIInputStream.m
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 10/08/2009.
|
||||
// Copyright 2009 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ASIInputStream.h"
|
||||
#import "ASIHTTPRequest.h"
|
||||
|
||||
// Used to ensure only one request can read data at once
|
||||
static NSLock *readLock = nil;
|
||||
|
||||
@implementation ASIInputStream
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
if (self == [ASIInputStream class]) {
|
||||
readLock = [[NSLock alloc] init];
|
||||
}
|
||||
}
|
||||
|
||||
+ (id)inputStreamWithFileAtPath:(NSString *)path request:(ASIHTTPRequest *)theRequest
|
||||
{
|
||||
ASIInputStream *theStream = [[[self alloc] init] autorelease];
|
||||
[theStream setRequest:theRequest];
|
||||
[theStream setStream:[NSInputStream inputStreamWithFileAtPath:path]];
|
||||
return theStream;
|
||||
}
|
||||
|
||||
+ (id)inputStreamWithData:(NSData *)data request:(ASIHTTPRequest *)theRequest
|
||||
{
|
||||
ASIInputStream *theStream = [[[self alloc] init] autorelease];
|
||||
[theStream setRequest:theRequest];
|
||||
[theStream setStream:[NSInputStream inputStreamWithData:data]];
|
||||
return theStream;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[stream release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
// Called when CFNetwork wants to read more of our request body
|
||||
// When throttling is on, we ask ASIHTTPRequest for the maximum amount of data we can read
|
||||
- (NSInteger)read:(uint8_t *)buffer maxLength:(NSUInteger)len
|
||||
{
|
||||
[readLock lock];
|
||||
unsigned long toRead = len;
|
||||
if ([ASIHTTPRequest isBandwidthThrottled]) {
|
||||
toRead = [ASIHTTPRequest maxUploadReadLength];
|
||||
if (toRead > len) {
|
||||
toRead = len;
|
||||
} else if (toRead == 0) {
|
||||
toRead = 1;
|
||||
}
|
||||
[request performThrottling];
|
||||
}
|
||||
[readLock unlock];
|
||||
NSInteger rv = [stream read:buffer maxLength:toRead];
|
||||
if (rv > 0)
|
||||
[ASIHTTPRequest incrementBandwidthUsedInLastSecond:rv];
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
* Implement NSInputStream mandatory methods to make sure they are implemented
|
||||
* (necessary for MacRuby for example) and avoid the overhead of method
|
||||
* forwarding for these common methods.
|
||||
*/
|
||||
- (void)open
|
||||
{
|
||||
[stream open];
|
||||
}
|
||||
|
||||
- (void)close
|
||||
{
|
||||
[stream close];
|
||||
}
|
||||
|
||||
- (id)delegate
|
||||
{
|
||||
return [stream delegate];
|
||||
}
|
||||
|
||||
- (void)setDelegate:(id)delegate
|
||||
{
|
||||
[stream setDelegate:delegate];
|
||||
}
|
||||
|
||||
- (void)scheduleInRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode
|
||||
{
|
||||
[stream scheduleInRunLoop:aRunLoop forMode:mode];
|
||||
}
|
||||
|
||||
- (void)removeFromRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode
|
||||
{
|
||||
[stream removeFromRunLoop:aRunLoop forMode:mode];
|
||||
}
|
||||
|
||||
- (id)propertyForKey:(NSString *)key
|
||||
{
|
||||
return [stream propertyForKey:key];
|
||||
}
|
||||
|
||||
- (BOOL)setProperty:(id)property forKey:(NSString *)key
|
||||
{
|
||||
return [stream setProperty:property forKey:key];
|
||||
}
|
||||
|
||||
- (NSStreamStatus)streamStatus
|
||||
{
|
||||
return [stream streamStatus];
|
||||
}
|
||||
|
||||
- (NSError *)streamError
|
||||
{
|
||||
return [stream streamError];
|
||||
}
|
||||
|
||||
// If we get asked to perform a method we don't have (probably internal ones),
|
||||
// we'll just forward the message to our stream
|
||||
|
||||
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
|
||||
{
|
||||
return [stream methodSignatureForSelector:aSelector];
|
||||
}
|
||||
|
||||
- (void)forwardInvocation:(NSInvocation *)anInvocation
|
||||
{
|
||||
[anInvocation invokeWithTarget:stream];
|
||||
}
|
||||
|
||||
@synthesize stream;
|
||||
@synthesize request;
|
||||
@end
|
||||
108
msext/Class/Common/ASIHttpRequest/.svn/text-base/ASINetworkQueue.h.svn-base
Executable file
108
msext/Class/Common/ASIHttpRequest/.svn/text-base/ASINetworkQueue.h.svn-base
Executable file
@@ -0,0 +1,108 @@
|
||||
//
|
||||
// ASINetworkQueue.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 07/11/2008.
|
||||
// Copyright 2008-2009 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "ASIHTTPRequestDelegate.h"
|
||||
#import "ASIProgressDelegate.h"
|
||||
|
||||
@interface ASINetworkQueue : NSOperationQueue <ASIProgressDelegate, ASIHTTPRequestDelegate, NSCopying> {
|
||||
|
||||
// Delegate will get didFail + didFinish messages (if set)
|
||||
id delegate;
|
||||
|
||||
// Will be called when a request starts with the request as the argument
|
||||
SEL requestDidStartSelector;
|
||||
|
||||
// Will be called when a request receives response headers
|
||||
// Should take the form request:didRecieveResponseHeaders:, where the first argument is the request, and the second the headers dictionary
|
||||
SEL requestDidReceiveResponseHeadersSelector;
|
||||
|
||||
// Will be called when a request is about to redirect
|
||||
// Should take the form request:willRedirectToURL:, where the first argument is the request, and the second the new url
|
||||
SEL requestWillRedirectSelector;
|
||||
|
||||
// Will be called when a request completes with the request as the argument
|
||||
SEL requestDidFinishSelector;
|
||||
|
||||
// Will be called when a request fails with the request as the argument
|
||||
SEL requestDidFailSelector;
|
||||
|
||||
// Will be called when the queue finishes with the queue as the argument
|
||||
SEL queueDidFinishSelector;
|
||||
|
||||
// Upload progress indicator, probably an NSProgressIndicator or UIProgressView
|
||||
id uploadProgressDelegate;
|
||||
|
||||
// Total amount uploaded so far for all requests in this queue
|
||||
unsigned long long bytesUploadedSoFar;
|
||||
|
||||
// Total amount to be uploaded for all requests in this queue - requests add to this figure as they work out how much data they have to transmit
|
||||
unsigned long long totalBytesToUpload;
|
||||
|
||||
// Download progress indicator, probably an NSProgressIndicator or UIProgressView
|
||||
id downloadProgressDelegate;
|
||||
|
||||
// Total amount downloaded so far for all requests in this queue
|
||||
unsigned long long bytesDownloadedSoFar;
|
||||
|
||||
// Total amount to be downloaded for all requests in this queue - requests add to this figure as they receive Content-Length headers
|
||||
unsigned long long totalBytesToDownload;
|
||||
|
||||
// When YES, the queue will cancel all requests when a request fails. Default is YES
|
||||
BOOL shouldCancelAllRequestsOnFailure;
|
||||
|
||||
//Number of real requests (excludes HEAD requests created to manage showAccurateProgress)
|
||||
int requestsCount;
|
||||
|
||||
// When NO, this request will only update the progress indicator when it completes
|
||||
// When YES, this request will update the progress indicator according to how much data it has received so far
|
||||
// When YES, the queue will first perform HEAD requests for all GET requests in the queue, so it can calculate the total download size before it starts
|
||||
// NO means better performance, because it skips this step for GET requests, and it won't waste time updating the progress indicator until a request completes
|
||||
// Set to YES if the size of a requests in the queue varies greatly for much more accurate results
|
||||
// Default for requests in the queue is NO
|
||||
BOOL showAccurateProgress;
|
||||
|
||||
// Storage container for additional queue information.
|
||||
NSDictionary *userInfo;
|
||||
|
||||
}
|
||||
|
||||
// Convenience constructor
|
||||
+ (id)queue;
|
||||
|
||||
// Call this to reset a queue - it will cancel all operations, clear delegates, and suspend operation
|
||||
- (void)reset;
|
||||
|
||||
// Used internally to manage HEAD requests when showAccurateProgress is YES, do not use!
|
||||
- (void)addHEADOperation:(NSOperation *)operation;
|
||||
|
||||
// All ASINetworkQueues are paused when created so that total size can be calculated before the queue starts
|
||||
// This method will start the queue
|
||||
- (void)go;
|
||||
|
||||
@property (assign, nonatomic, setter=setUploadProgressDelegate:) id uploadProgressDelegate;
|
||||
@property (assign, nonatomic, setter=setDownloadProgressDelegate:) id downloadProgressDelegate;
|
||||
|
||||
@property (assign) SEL requestDidStartSelector;
|
||||
@property (assign) SEL requestDidReceiveResponseHeadersSelector;
|
||||
@property (assign) SEL requestWillRedirectSelector;
|
||||
@property (assign) SEL requestDidFinishSelector;
|
||||
@property (assign) SEL requestDidFailSelector;
|
||||
@property (assign) SEL queueDidFinishSelector;
|
||||
@property (assign) BOOL shouldCancelAllRequestsOnFailure;
|
||||
@property (assign) id delegate;
|
||||
@property (assign) BOOL showAccurateProgress;
|
||||
@property (assign, readonly) int requestsCount;
|
||||
@property (retain) NSDictionary *userInfo;
|
||||
|
||||
@property (assign) unsigned long long bytesUploadedSoFar;
|
||||
@property (assign) unsigned long long totalBytesToUpload;
|
||||
@property (assign) unsigned long long bytesDownloadedSoFar;
|
||||
@property (assign) unsigned long long totalBytesToDownload;
|
||||
|
||||
@end
|
||||
343
msext/Class/Common/ASIHttpRequest/.svn/text-base/ASINetworkQueue.m.svn-base
Executable file
343
msext/Class/Common/ASIHttpRequest/.svn/text-base/ASINetworkQueue.m.svn-base
Executable file
@@ -0,0 +1,343 @@
|
||||
//
|
||||
// ASINetworkQueue.m
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 07/11/2008.
|
||||
// Copyright 2008-2009 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ASINetworkQueue.h"
|
||||
#import "ASIHTTPRequest.h"
|
||||
|
||||
// Private stuff
|
||||
@interface ASINetworkQueue ()
|
||||
- (void)resetProgressDelegate:(id *)progressDelegate;
|
||||
@property (assign) int requestsCount;
|
||||
@end
|
||||
|
||||
@implementation ASINetworkQueue
|
||||
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
[self setShouldCancelAllRequestsOnFailure:YES];
|
||||
[self setMaxConcurrentOperationCount:4];
|
||||
[self setSuspended:YES];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (id)queue
|
||||
{
|
||||
return [[[self alloc] init] autorelease];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
//We need to clear the queue on any requests that haven't got around to cleaning up yet, as otherwise they'll try to let us know if something goes wrong, and we'll be long gone by then
|
||||
for (ASIHTTPRequest *request in [self operations]) {
|
||||
[request setQueue:nil];
|
||||
}
|
||||
[userInfo release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void)setSuspended:(BOOL)suspend
|
||||
{
|
||||
[super setSuspended:suspend];
|
||||
}
|
||||
|
||||
- (void)reset
|
||||
{
|
||||
[self cancelAllOperations];
|
||||
[self setDelegate:nil];
|
||||
[self setDownloadProgressDelegate:nil];
|
||||
[self setUploadProgressDelegate:nil];
|
||||
[self setRequestDidStartSelector:NULL];
|
||||
[self setRequestDidReceiveResponseHeadersSelector:NULL];
|
||||
[self setRequestDidFailSelector:NULL];
|
||||
[self setRequestDidFinishSelector:NULL];
|
||||
[self setQueueDidFinishSelector:NULL];
|
||||
[self setSuspended:YES];
|
||||
}
|
||||
|
||||
|
||||
- (void)go
|
||||
{
|
||||
[self setSuspended:NO];
|
||||
}
|
||||
|
||||
- (void)cancelAllOperations
|
||||
{
|
||||
[self setBytesUploadedSoFar:0];
|
||||
[self setTotalBytesToUpload:0];
|
||||
[self setBytesDownloadedSoFar:0];
|
||||
[self setTotalBytesToDownload:0];
|
||||
[super cancelAllOperations];
|
||||
}
|
||||
|
||||
- (void)setUploadProgressDelegate:(id)newDelegate
|
||||
{
|
||||
uploadProgressDelegate = newDelegate;
|
||||
[self resetProgressDelegate:&uploadProgressDelegate];
|
||||
|
||||
}
|
||||
|
||||
- (void)setDownloadProgressDelegate:(id)newDelegate
|
||||
{
|
||||
downloadProgressDelegate = newDelegate;
|
||||
[self resetProgressDelegate:&downloadProgressDelegate];
|
||||
}
|
||||
|
||||
- (void)resetProgressDelegate:(id *)progressDelegate
|
||||
{
|
||||
#if !TARGET_OS_IPHONE
|
||||
// If the uploadProgressDelegate is an NSProgressIndicator, we set its MaxValue to 1.0 so we can treat it similarly to UIProgressViews
|
||||
SEL selector = @selector(setMaxValue:);
|
||||
if ([*progressDelegate respondsToSelector:selector]) {
|
||||
double max = 1.0;
|
||||
[ASIHTTPRequest performSelector:selector onTarget:progressDelegate withObject:nil amount:&max callerToRetain:nil];
|
||||
}
|
||||
selector = @selector(setDoubleValue:);
|
||||
if ([*progressDelegate respondsToSelector:selector]) {
|
||||
double value = 0.0;
|
||||
[ASIHTTPRequest performSelector:selector onTarget:progressDelegate withObject:nil amount:&value callerToRetain:nil];
|
||||
}
|
||||
#else
|
||||
SEL selector = @selector(setProgress:);
|
||||
if ([*progressDelegate respondsToSelector:selector]) {
|
||||
float value = 0.0f;
|
||||
[ASIHTTPRequest performSelector:selector onTarget:progressDelegate withObject:nil amount:&value callerToRetain:nil];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)addHEADOperation:(NSOperation *)operation
|
||||
{
|
||||
if ([operation isKindOfClass:[ASIHTTPRequest class]]) {
|
||||
|
||||
ASIHTTPRequest *request = (ASIHTTPRequest *)operation;
|
||||
[request setRequestMethod:@"HEAD"];
|
||||
[request setQueuePriority:10];
|
||||
[request setShowAccurateProgress:YES];
|
||||
[request setQueue:self];
|
||||
|
||||
// Important - we are calling NSOperation's add method - we don't want to add this as a normal request!
|
||||
[super addOperation:request];
|
||||
}
|
||||
}
|
||||
|
||||
// Only add ASIHTTPRequests to this queue!!
|
||||
- (void)addOperation:(NSOperation *)operation
|
||||
{
|
||||
if (![operation isKindOfClass:[ASIHTTPRequest class]]) {
|
||||
[NSException raise:@"AttemptToAddInvalidRequest" format:@"Attempted to add an object that was not an ASIHTTPRequest to an ASINetworkQueue"];
|
||||
}
|
||||
|
||||
[self setRequestsCount:[self requestsCount]+1];
|
||||
|
||||
ASIHTTPRequest *request = (ASIHTTPRequest *)operation;
|
||||
|
||||
if ([self showAccurateProgress]) {
|
||||
|
||||
// Force the request to build its body (this may change requestMethod)
|
||||
[request buildPostBody];
|
||||
|
||||
// If this is a GET request and we want accurate progress, perform a HEAD request first to get the content-length
|
||||
// We'll only do this before the queue is started
|
||||
// If requests are added after the queue is started they will probably move the overall progress backwards anyway, so there's no value performing the HEAD requests first
|
||||
// Instead, they'll update the total progress if and when they receive a content-length header
|
||||
if ([[request requestMethod] isEqualToString:@"GET"]) {
|
||||
if ([self isSuspended]) {
|
||||
ASIHTTPRequest *HEADRequest = [request HEADRequest];
|
||||
[self addHEADOperation:HEADRequest];
|
||||
[request addDependency:HEADRequest];
|
||||
if ([request shouldResetDownloadProgress]) {
|
||||
[self resetProgressDelegate:&downloadProgressDelegate];
|
||||
[request setShouldResetDownloadProgress:NO];
|
||||
}
|
||||
}
|
||||
}
|
||||
[request buildPostBody];
|
||||
[self request:nil incrementUploadSizeBy:[request postLength]];
|
||||
|
||||
|
||||
} else {
|
||||
[self request:nil incrementDownloadSizeBy:1];
|
||||
[self request:nil incrementUploadSizeBy:1];
|
||||
}
|
||||
// Tell the request not to increment the upload size when it starts, as we've already added its length
|
||||
if ([request shouldResetUploadProgress]) {
|
||||
[self resetProgressDelegate:&uploadProgressDelegate];
|
||||
[request setShouldResetUploadProgress:NO];
|
||||
}
|
||||
|
||||
[request setShowAccurateProgress:[self showAccurateProgress]];
|
||||
|
||||
[request setQueue:self];
|
||||
[super addOperation:request];
|
||||
|
||||
}
|
||||
|
||||
- (void)requestStarted:(ASIHTTPRequest *)request
|
||||
{
|
||||
if ([self requestDidStartSelector]) {
|
||||
[[self delegate] performSelector:[self requestDidStartSelector] withObject:request];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)request:(ASIHTTPRequest *)request didReceiveResponseHeaders:(NSDictionary *)responseHeaders
|
||||
{
|
||||
if ([self requestDidReceiveResponseHeadersSelector]) {
|
||||
[[self delegate] performSelector:[self requestDidReceiveResponseHeadersSelector] withObject:request withObject:responseHeaders];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)request:(ASIHTTPRequest *)request willRedirectToURL:(NSURL *)newURL
|
||||
{
|
||||
if ([self requestWillRedirectSelector]) {
|
||||
[[self delegate] performSelector:[self requestWillRedirectSelector] withObject:request withObject:newURL];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)requestFinished:(ASIHTTPRequest *)request
|
||||
{
|
||||
[self setRequestsCount:[self requestsCount]-1];
|
||||
if ([self requestDidFinishSelector]) {
|
||||
[[self delegate] performSelector:[self requestDidFinishSelector] withObject:request];
|
||||
}
|
||||
if ([self requestsCount] == 0) {
|
||||
if ([self queueDidFinishSelector]) {
|
||||
[[self delegate] performSelector:[self queueDidFinishSelector] withObject:self];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)requestFailed:(ASIHTTPRequest *)request
|
||||
{
|
||||
[self setRequestsCount:[self requestsCount]-1];
|
||||
if ([self requestDidFailSelector]) {
|
||||
[[self delegate] performSelector:[self requestDidFailSelector] withObject:request];
|
||||
}
|
||||
if ([self requestsCount] == 0) {
|
||||
if ([self queueDidFinishSelector]) {
|
||||
[[self delegate] performSelector:[self queueDidFinishSelector] withObject:self];
|
||||
}
|
||||
}
|
||||
if ([self shouldCancelAllRequestsOnFailure] && [self requestsCount] > 0) {
|
||||
[self cancelAllOperations];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
- (void)request:(ASIHTTPRequest *)request didReceiveBytes:(long long)bytes
|
||||
{
|
||||
[self setBytesDownloadedSoFar:[self bytesDownloadedSoFar]+bytes];
|
||||
if ([self downloadProgressDelegate]) {
|
||||
[ASIHTTPRequest updateProgressIndicator:&downloadProgressDelegate withProgress:[self bytesDownloadedSoFar] ofTotal:[self totalBytesToDownload]];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)request:(ASIHTTPRequest *)request didSendBytes:(long long)bytes
|
||||
{
|
||||
[self setBytesUploadedSoFar:[self bytesUploadedSoFar]+bytes];
|
||||
if ([self uploadProgressDelegate]) {
|
||||
[ASIHTTPRequest updateProgressIndicator:&uploadProgressDelegate withProgress:[self bytesUploadedSoFar] ofTotal:[self totalBytesToUpload]];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)request:(ASIHTTPRequest *)request incrementDownloadSizeBy:(long long)newLength
|
||||
{
|
||||
[self setTotalBytesToDownload:[self totalBytesToDownload]+newLength];
|
||||
}
|
||||
|
||||
- (void)request:(ASIHTTPRequest *)request incrementUploadSizeBy:(long long)newLength
|
||||
{
|
||||
[self setTotalBytesToUpload:[self totalBytesToUpload]+newLength];
|
||||
}
|
||||
|
||||
|
||||
// Since this queue takes over as the delegate for all requests it contains, it should forward authorisation requests to its own delegate
|
||||
- (void)authenticationNeededForRequest:(ASIHTTPRequest *)request
|
||||
{
|
||||
if ([[self delegate] respondsToSelector:@selector(authenticationNeededForRequest:)]) {
|
||||
[[self delegate] performSelector:@selector(authenticationNeededForRequest:) withObject:request];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)proxyAuthenticationNeededForRequest:(ASIHTTPRequest *)request
|
||||
{
|
||||
if ([[self delegate] respondsToSelector:@selector(proxyAuthenticationNeededForRequest:)]) {
|
||||
[[self delegate] performSelector:@selector(proxyAuthenticationNeededForRequest:) withObject:request];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (BOOL)respondsToSelector:(SEL)selector
|
||||
{
|
||||
// We handle certain methods differently because whether our delegate implements them or not can affect how the request should behave
|
||||
|
||||
// If the delegate implements this, the request will stop to wait for credentials
|
||||
if (selector == @selector(authenticationNeededForRequest:)) {
|
||||
if ([[self delegate] respondsToSelector:@selector(authenticationNeededForRequest:)]) {
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
|
||||
// If the delegate implements this, the request will to wait for credentials
|
||||
} else if (selector == @selector(proxyAuthenticationNeededForRequest:)) {
|
||||
if ([[self delegate] respondsToSelector:@selector(proxyAuthenticationNeededForRequest:)]) {
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
|
||||
// If the delegate implements requestWillRedirectSelector, the request will stop to allow the delegate to change the url
|
||||
} else if (selector == @selector(request:willRedirectToURL:)) {
|
||||
if ([self requestWillRedirectSelector] && [[self delegate] respondsToSelector:[self requestWillRedirectSelector]]) {
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
return [super respondsToSelector:selector];
|
||||
}
|
||||
|
||||
#pragma mark NSCopying
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
ASINetworkQueue *newQueue = [[[self class] alloc] init];
|
||||
[newQueue setDelegate:[self delegate]];
|
||||
[newQueue setRequestDidStartSelector:[self requestDidStartSelector]];
|
||||
[newQueue setRequestWillRedirectSelector:[self requestWillRedirectSelector]];
|
||||
[newQueue setRequestDidReceiveResponseHeadersSelector:[self requestDidReceiveResponseHeadersSelector]];
|
||||
[newQueue setRequestDidFinishSelector:[self requestDidFinishSelector]];
|
||||
[newQueue setRequestDidFailSelector:[self requestDidFailSelector]];
|
||||
[newQueue setQueueDidFinishSelector:[self queueDidFinishSelector]];
|
||||
[newQueue setUploadProgressDelegate:[self uploadProgressDelegate]];
|
||||
[newQueue setDownloadProgressDelegate:[self downloadProgressDelegate]];
|
||||
[newQueue setShouldCancelAllRequestsOnFailure:[self shouldCancelAllRequestsOnFailure]];
|
||||
[newQueue setShowAccurateProgress:[self showAccurateProgress]];
|
||||
[newQueue setUserInfo:[[[self userInfo] copyWithZone:zone] autorelease]];
|
||||
return newQueue;
|
||||
}
|
||||
|
||||
|
||||
@synthesize requestsCount;
|
||||
@synthesize bytesUploadedSoFar;
|
||||
@synthesize totalBytesToUpload;
|
||||
@synthesize bytesDownloadedSoFar;
|
||||
@synthesize totalBytesToDownload;
|
||||
@synthesize shouldCancelAllRequestsOnFailure;
|
||||
@synthesize uploadProgressDelegate;
|
||||
@synthesize downloadProgressDelegate;
|
||||
@synthesize requestDidStartSelector;
|
||||
@synthesize requestDidReceiveResponseHeadersSelector;
|
||||
@synthesize requestWillRedirectSelector;
|
||||
@synthesize requestDidFinishSelector;
|
||||
@synthesize requestDidFailSelector;
|
||||
@synthesize queueDidFinishSelector;
|
||||
@synthesize delegate;
|
||||
@synthesize showAccurateProgress;
|
||||
@synthesize userInfo;
|
||||
@end
|
||||
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// ASIProgressDelegate.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 13/04/2010.
|
||||
// Copyright 2010 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
@class ASIHTTPRequest;
|
||||
|
||||
@protocol ASIProgressDelegate <NSObject>
|
||||
|
||||
@optional
|
||||
|
||||
// These methods are used to update UIProgressViews (iPhone OS) or NSProgressIndicators (Mac OS X)
|
||||
// If you are using a custom progress delegate, you may find it easier to implement didReceiveBytes / didSendBytes instead
|
||||
#if TARGET_OS_IPHONE
|
||||
- (void)setProgress:(float)newProgress;
|
||||
#else
|
||||
- (void)setDoubleValue:(double)newProgress;
|
||||
- (void)setMaxValue:(double)newMax;
|
||||
#endif
|
||||
|
||||
// Called when the request receives some data - bytes is the length of that data
|
||||
- (void)request:(ASIHTTPRequest *)request didReceiveBytes:(long long)bytes;
|
||||
|
||||
// Called when the request sends some data
|
||||
// The first 32KB (128KB on older platforms) of data sent is not included in this amount because of limitations with the CFNetwork API
|
||||
// bytes may be less than zero if a request needs to remove upload progress (probably because the request needs to run again)
|
||||
- (void)request:(ASIHTTPRequest *)request didSendBytes:(long long)bytes;
|
||||
|
||||
// Called when a request needs to change the length of the content to download
|
||||
- (void)request:(ASIHTTPRequest *)request incrementDownloadSizeBy:(long long)newLength;
|
||||
|
||||
// Called when a request needs to change the length of the content to upload
|
||||
// newLength may be less than zero when a request needs to remove the size of the internal buffer from progress tracking
|
||||
- (void)request:(ASIHTTPRequest *)request incrementUploadSizeBy:(long long)newLength;
|
||||
@end
|
||||
35
msext/Class/Common/ASIHttpRequest/ASIAuthenticationDialog.h
Executable file
35
msext/Class/Common/ASIHttpRequest/ASIAuthenticationDialog.h
Executable file
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// ASIAuthenticationDialog.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 21/08/2009.
|
||||
// Copyright 2009 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
@class ASIHTTPRequest;
|
||||
|
||||
typedef enum _ASIAuthenticationType {
|
||||
ASIStandardAuthenticationType = 0,
|
||||
ASIProxyAuthenticationType = 1
|
||||
} ASIAuthenticationType;
|
||||
|
||||
@interface ASIAutorotatingViewController : UIViewController
|
||||
@end
|
||||
|
||||
@interface ASIAuthenticationDialog : ASIAutorotatingViewController <UIActionSheetDelegate, UITableViewDelegate, UITableViewDataSource> {
|
||||
ASIHTTPRequest *request;
|
||||
ASIAuthenticationType type;
|
||||
UITableView *tableView;
|
||||
UIViewController *presentingController;
|
||||
BOOL didEnableRotationNotifications;
|
||||
}
|
||||
+ (void)presentAuthenticationDialogForRequest:(ASIHTTPRequest *)request;
|
||||
+ (void)dismiss;
|
||||
|
||||
@property (retain) ASIHTTPRequest *request;
|
||||
@property (assign) ASIAuthenticationType type;
|
||||
@property (assign) BOOL didEnableRotationNotifications;
|
||||
@property (retain, nonatomic) UIViewController *presentingController;
|
||||
@end
|
||||
493
msext/Class/Common/ASIHttpRequest/ASIAuthenticationDialog.m
Executable file
493
msext/Class/Common/ASIHttpRequest/ASIAuthenticationDialog.m
Executable file
@@ -0,0 +1,493 @@
|
||||
//
|
||||
// ASIAuthenticationDialog.m
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 21/08/2009.
|
||||
// Copyright 2009 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ASIAuthenticationDialog.h"
|
||||
#import "ASIHTTPRequest.h"
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
|
||||
static ASIAuthenticationDialog *sharedDialog = nil;
|
||||
BOOL isDismissing = NO;
|
||||
static NSMutableArray *requestsNeedingAuthentication = nil;
|
||||
|
||||
static const NSUInteger kUsernameRow = 0;
|
||||
static const NSUInteger kUsernameSection = 0;
|
||||
static const NSUInteger kPasswordRow = 1;
|
||||
static const NSUInteger kPasswordSection = 0;
|
||||
static const NSUInteger kDomainRow = 0;
|
||||
static const NSUInteger kDomainSection = 1;
|
||||
|
||||
|
||||
@implementation ASIAutorotatingViewController
|
||||
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface ASIAuthenticationDialog ()
|
||||
- (void)showTitle;
|
||||
- (void)show;
|
||||
- (NSArray *)requestsRequiringTheseCredentials;
|
||||
- (void)presentNextDialog;
|
||||
- (void)keyboardWillShow:(NSNotification *)notification;
|
||||
- (void)orientationChanged:(NSNotification *)notification;
|
||||
- (void)cancelAuthenticationFromDialog:(id)sender;
|
||||
- (void)loginWithCredentialsFromDialog:(id)sender;
|
||||
@property (retain) UITableView *tableView;
|
||||
@end
|
||||
|
||||
@implementation ASIAuthenticationDialog
|
||||
|
||||
#pragma mark init / dealloc
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
if (self == [ASIAuthenticationDialog class]) {
|
||||
requestsNeedingAuthentication = [[NSMutableArray array] retain];
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)presentAuthenticationDialogForRequest:(ASIHTTPRequest *)theRequest
|
||||
{
|
||||
// No need for a lock here, this will always be called on the main thread
|
||||
if (!sharedDialog) {
|
||||
sharedDialog = [[self alloc] init];
|
||||
[sharedDialog setRequest:theRequest];
|
||||
if ([theRequest authenticationNeeded] == ASIProxyAuthenticationNeeded) {
|
||||
[sharedDialog setType:ASIProxyAuthenticationType];
|
||||
} else {
|
||||
[sharedDialog setType:ASIStandardAuthenticationType];
|
||||
}
|
||||
[sharedDialog show];
|
||||
} else {
|
||||
[requestsNeedingAuthentication addObject:theRequest];
|
||||
}
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if ((self = [self initWithNibName:nil bundle:nil])) {
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
|
||||
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2
|
||||
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
|
||||
#endif
|
||||
if (![UIDevice currentDevice].generatesDeviceOrientationNotifications) {
|
||||
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
|
||||
[self setDidEnableRotationNotifications:YES];
|
||||
}
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:nil];
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
if ([self didEnableRotationNotifications]) {
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil];
|
||||
}
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
|
||||
|
||||
[request release];
|
||||
[tableView release];
|
||||
[presentingController.view removeFromSuperview];
|
||||
[presentingController release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
#pragma mark keyboard notifications
|
||||
|
||||
- (void)keyboardWillShow:(NSNotification *)notification
|
||||
{
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2
|
||||
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
|
||||
#endif
|
||||
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_3_2
|
||||
NSValue *keyboardBoundsValue = [[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey];
|
||||
#else
|
||||
NSValue *keyboardBoundsValue = [[notification userInfo] objectForKey:UIKeyboardBoundsUserInfoKey];
|
||||
#endif
|
||||
CGRect keyboardBounds;
|
||||
[keyboardBoundsValue getValue:&keyboardBounds];
|
||||
UIEdgeInsets e = UIEdgeInsetsMake(0, 0, keyboardBounds.size.height, 0);
|
||||
[[self tableView] setScrollIndicatorInsets:e];
|
||||
[[self tableView] setContentInset:e];
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Manually handles orientation changes on iPhone
|
||||
- (void)orientationChanged:(NSNotification *)notification
|
||||
{
|
||||
[self showTitle];
|
||||
|
||||
UIInterfaceOrientation o = (UIInterfaceOrientation)[[UIApplication sharedApplication] statusBarOrientation];
|
||||
CGFloat angle = 0;
|
||||
switch (o) {
|
||||
case UIDeviceOrientationLandscapeLeft: angle = 90; break;
|
||||
case UIDeviceOrientationLandscapeRight: angle = -90; break;
|
||||
case UIDeviceOrientationPortraitUpsideDown: angle = 180; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
CGRect f = [[UIScreen mainScreen] applicationFrame];
|
||||
|
||||
// Swap the frame height and width if necessary
|
||||
if (UIDeviceOrientationIsLandscape(o)) {
|
||||
CGFloat t;
|
||||
t = f.size.width;
|
||||
f.size.width = f.size.height;
|
||||
f.size.height = t;
|
||||
}
|
||||
|
||||
CGAffineTransform previousTransform = self.view.layer.affineTransform;
|
||||
CGAffineTransform newTransform = CGAffineTransformMakeRotation((CGFloat)(angle * M_PI / 180.0));
|
||||
|
||||
// Reset the transform so we can set the size
|
||||
self.view.layer.affineTransform = CGAffineTransformIdentity;
|
||||
self.view.frame = (CGRect){ { 0, 0 }, f.size};
|
||||
|
||||
// Revert to the previous transform for correct animation
|
||||
self.view.layer.affineTransform = previousTransform;
|
||||
|
||||
[UIView beginAnimations:nil context:NULL];
|
||||
[UIView setAnimationDuration:0.3];
|
||||
|
||||
// Set the new transform
|
||||
self.view.layer.affineTransform = newTransform;
|
||||
|
||||
// Fix the view origin
|
||||
self.view.frame = (CGRect){ { f.origin.x, f.origin.y },self.view.frame.size};
|
||||
[UIView commitAnimations];
|
||||
}
|
||||
|
||||
#pragma mark utilities
|
||||
|
||||
- (UIViewController *)presentingController
|
||||
{
|
||||
if (!presentingController) {
|
||||
presentingController = [[ASIAutorotatingViewController alloc] initWithNibName:nil bundle:nil];
|
||||
|
||||
// Attach to the window, but don't interfere.
|
||||
UIWindow *window = [[[UIApplication sharedApplication] windows] objectAtIndex:0];
|
||||
[window addSubview:[presentingController view]];
|
||||
[[presentingController view] setFrame:CGRectZero];
|
||||
[[presentingController view] setUserInteractionEnabled:NO];
|
||||
}
|
||||
|
||||
return presentingController;
|
||||
}
|
||||
|
||||
- (UITextField *)textFieldInRow:(NSUInteger)row section:(NSUInteger)section
|
||||
{
|
||||
return [[[[[self tableView] cellForRowAtIndexPath:
|
||||
[NSIndexPath indexPathForRow:row inSection:section]]
|
||||
contentView] subviews] objectAtIndex:0];
|
||||
}
|
||||
|
||||
- (UITextField *)usernameField
|
||||
{
|
||||
return [self textFieldInRow:kUsernameRow section:kUsernameSection];
|
||||
}
|
||||
|
||||
- (UITextField *)passwordField
|
||||
{
|
||||
return [self textFieldInRow:kPasswordRow section:kPasswordSection];
|
||||
}
|
||||
|
||||
- (UITextField *)domainField
|
||||
{
|
||||
return [self textFieldInRow:kDomainRow section:kDomainSection];
|
||||
}
|
||||
|
||||
#pragma mark show / dismiss
|
||||
|
||||
+ (void)dismiss
|
||||
{
|
||||
if ([sharedDialog respondsToSelector:@selector(presentingViewController)])
|
||||
[[sharedDialog presentingViewController] dismissModalViewControllerAnimated:YES];
|
||||
else
|
||||
[[sharedDialog parentViewController] dismissModalViewControllerAnimated:YES];
|
||||
}
|
||||
|
||||
- (void)viewDidDisappear:(BOOL)animated
|
||||
{
|
||||
[self retain];
|
||||
[sharedDialog release];
|
||||
sharedDialog = nil;
|
||||
[self performSelector:@selector(presentNextDialog) withObject:nil afterDelay:0];
|
||||
[self release];
|
||||
}
|
||||
|
||||
- (void)dismiss
|
||||
{
|
||||
if (self == sharedDialog) {
|
||||
[[self class] dismiss];
|
||||
} else {
|
||||
if ([self respondsToSelector:@selector(presentingViewController)])
|
||||
[[self presentingViewController] dismissModalViewControllerAnimated:YES];
|
||||
else
|
||||
[[self parentViewController] dismissModalViewControllerAnimated:YES];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)showTitle
|
||||
{
|
||||
UINavigationBar *navigationBar = [[[self view] subviews] objectAtIndex:0];
|
||||
UINavigationItem *navItem = [[navigationBar items] objectAtIndex:0];
|
||||
if (UIInterfaceOrientationIsPortrait([[UIDevice currentDevice] orientation])) {
|
||||
// Setup the title
|
||||
if ([self type] == ASIProxyAuthenticationType) {
|
||||
[navItem setPrompt:@"Login to this secure proxy server."];
|
||||
} else {
|
||||
[navItem setPrompt:@"Login to this secure server."];
|
||||
}
|
||||
} else {
|
||||
[navItem setPrompt:nil];
|
||||
}
|
||||
[navigationBar sizeToFit];
|
||||
CGRect f = [[self view] bounds];
|
||||
f.origin.y = [navigationBar frame].size.height;
|
||||
f.size.height -= f.origin.y;
|
||||
[[self tableView] setFrame:f];
|
||||
}
|
||||
|
||||
- (void)show
|
||||
{
|
||||
// Remove all subviews
|
||||
UIView *v;
|
||||
while ((v = [[[self view] subviews] lastObject])) {
|
||||
[v removeFromSuperview];
|
||||
}
|
||||
|
||||
// Setup toolbar
|
||||
UINavigationBar *bar = [[[UINavigationBar alloc] init] autorelease];
|
||||
[bar setAutoresizingMask:UIViewAutoresizingFlexibleWidth];
|
||||
|
||||
UINavigationItem *navItem = [[[UINavigationItem alloc] init] autorelease];
|
||||
bar.items = [NSArray arrayWithObject:navItem];
|
||||
|
||||
[[self view] addSubview:bar];
|
||||
|
||||
[self showTitle];
|
||||
|
||||
// Setup toolbar buttons
|
||||
if ([self type] == ASIProxyAuthenticationType) {
|
||||
[navItem setTitle:[[self request] proxyHost]];
|
||||
} else {
|
||||
[navItem setTitle:[[[self request] url] host]];
|
||||
}
|
||||
|
||||
[navItem setLeftBarButtonItem:[[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancelAuthenticationFromDialog:)] autorelease]];
|
||||
[navItem setRightBarButtonItem:[[[UIBarButtonItem alloc] initWithTitle:@"Login" style:UIBarButtonItemStyleDone target:self action:@selector(loginWithCredentialsFromDialog:)] autorelease]];
|
||||
|
||||
// We show the login form in a table view, similar to Safari's authentication dialog
|
||||
[bar sizeToFit];
|
||||
CGRect f = [[self view] bounds];
|
||||
f.origin.y = [bar frame].size.height;
|
||||
f.size.height -= f.origin.y;
|
||||
|
||||
[self setTableView:[[[UITableView alloc] initWithFrame:f style:UITableViewStyleGrouped] autorelease]];
|
||||
[[self tableView] setDelegate:self];
|
||||
[[self tableView] setDataSource:self];
|
||||
[[self tableView] setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
|
||||
[[self view] addSubview:[self tableView]];
|
||||
|
||||
// Force reload the table content, and focus the first field to show the keyboard
|
||||
[[self tableView] reloadData];
|
||||
[[[[[self tableView] cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]].contentView subviews] objectAtIndex:0] becomeFirstResponder];
|
||||
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2
|
||||
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
|
||||
[self setModalPresentationStyle:UIModalPresentationFormSheet];
|
||||
}
|
||||
#endif
|
||||
|
||||
[[self presentingController] presentModalViewController:self animated:YES];
|
||||
}
|
||||
|
||||
#pragma mark button callbacks
|
||||
|
||||
- (void)cancelAuthenticationFromDialog:(id)sender
|
||||
{
|
||||
for (ASIHTTPRequest *theRequest in [self requestsRequiringTheseCredentials]) {
|
||||
[theRequest cancelAuthentication];
|
||||
[requestsNeedingAuthentication removeObject:theRequest];
|
||||
}
|
||||
[self dismiss];
|
||||
}
|
||||
|
||||
- (NSArray *)requestsRequiringTheseCredentials
|
||||
{
|
||||
NSMutableArray *requestsRequiringTheseCredentials = [NSMutableArray array];
|
||||
NSURL *requestURL = [[self request] url];
|
||||
for (ASIHTTPRequest *otherRequest in requestsNeedingAuthentication) {
|
||||
NSURL *theURL = [otherRequest url];
|
||||
if (([otherRequest authenticationNeeded] == [[self request] authenticationNeeded]) && [[theURL host] isEqualToString:[requestURL host]] && ([theURL port] == [requestURL port] || ([requestURL port] && [[theURL port] isEqualToNumber:[requestURL port]])) && [[theURL scheme] isEqualToString:[requestURL scheme]] && ((![otherRequest authenticationRealm] && ![[self request] authenticationRealm]) || ([otherRequest authenticationRealm] && [[self request] authenticationRealm] && [[[self request] authenticationRealm] isEqualToString:[otherRequest authenticationRealm]]))) {
|
||||
[requestsRequiringTheseCredentials addObject:otherRequest];
|
||||
}
|
||||
}
|
||||
[requestsRequiringTheseCredentials addObject:[self request]];
|
||||
return requestsRequiringTheseCredentials;
|
||||
}
|
||||
|
||||
- (void)presentNextDialog
|
||||
{
|
||||
if ([requestsNeedingAuthentication count]) {
|
||||
ASIHTTPRequest *nextRequest = [requestsNeedingAuthentication objectAtIndex:0];
|
||||
[requestsNeedingAuthentication removeObjectAtIndex:0];
|
||||
[[self class] presentAuthenticationDialogForRequest:nextRequest];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void)loginWithCredentialsFromDialog:(id)sender
|
||||
{
|
||||
for (ASIHTTPRequest *theRequest in [self requestsRequiringTheseCredentials]) {
|
||||
|
||||
NSString *username = [[self usernameField] text];
|
||||
NSString *password = [[self passwordField] text];
|
||||
|
||||
if (username == nil) { username = @""; }
|
||||
if (password == nil) { password = @""; }
|
||||
|
||||
if ([self type] == ASIProxyAuthenticationType) {
|
||||
[theRequest setProxyUsername:username];
|
||||
[theRequest setProxyPassword:password];
|
||||
} else {
|
||||
[theRequest setUsername:username];
|
||||
[theRequest setPassword:password];
|
||||
}
|
||||
|
||||
// Handle NTLM domains
|
||||
NSString *scheme = ([self type] == ASIStandardAuthenticationType) ? [[self request] authenticationScheme] : [[self request] proxyAuthenticationScheme];
|
||||
if ([scheme isEqualToString:(NSString *)kCFHTTPAuthenticationSchemeNTLM]) {
|
||||
NSString *domain = [[self domainField] text];
|
||||
if ([self type] == ASIProxyAuthenticationType) {
|
||||
[theRequest setProxyDomain:domain];
|
||||
} else {
|
||||
[theRequest setDomain:domain];
|
||||
}
|
||||
}
|
||||
|
||||
[theRequest retryUsingSuppliedCredentials];
|
||||
[requestsNeedingAuthentication removeObject:theRequest];
|
||||
}
|
||||
[self dismiss];
|
||||
}
|
||||
|
||||
#pragma mark table view data source
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)aTableView
|
||||
{
|
||||
NSString *scheme = ([self type] == ASIStandardAuthenticationType) ? [[self request] authenticationScheme] : [[self request] proxyAuthenticationScheme];
|
||||
if ([scheme isEqualToString:(NSString *)kCFHTTPAuthenticationSchemeNTLM]) {
|
||||
return 2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
- (CGFloat)tableView:(UITableView *)aTableView heightForFooterInSection:(NSInteger)section
|
||||
{
|
||||
if (section == [self numberOfSectionsInTableView:aTableView]-1) {
|
||||
return 30;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (CGFloat)tableView:(UITableView *)aTableView heightForHeaderInSection:(NSInteger)section
|
||||
{
|
||||
if (section == 0) {
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2
|
||||
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
|
||||
return 54;
|
||||
}
|
||||
#endif
|
||||
return 30;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
|
||||
{
|
||||
if (section == 0) {
|
||||
return [[self request] authenticationRealm];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_3_0
|
||||
UITableViewCell *cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil] autorelease];
|
||||
#else
|
||||
UITableViewCell *cell = [[[UITableViewCell alloc] initWithFrame:CGRectMake(0,0,0,0) reuseIdentifier:nil] autorelease];
|
||||
#endif
|
||||
|
||||
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
|
||||
|
||||
CGRect f = CGRectInset([cell bounds], 10, 10);
|
||||
UITextField *textField = [[[UITextField alloc] initWithFrame:f] autorelease];
|
||||
[textField setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
|
||||
[textField setAutocapitalizationType:UITextAutocapitalizationTypeNone];
|
||||
[textField setAutocorrectionType:UITextAutocorrectionTypeNo];
|
||||
|
||||
NSUInteger s = [indexPath section];
|
||||
NSUInteger r = [indexPath row];
|
||||
|
||||
if (s == kUsernameSection && r == kUsernameRow) {
|
||||
[textField setPlaceholder:@"User"];
|
||||
} else if (s == kPasswordSection && r == kPasswordRow) {
|
||||
[textField setPlaceholder:@"Password"];
|
||||
[textField setSecureTextEntry:YES];
|
||||
} else if (s == kDomainSection && r == kDomainRow) {
|
||||
[textField setPlaceholder:@"Domain"];
|
||||
}
|
||||
[cell.contentView addSubview:textField];
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)aTableView numberOfRowsInSection:(NSInteger)section
|
||||
{
|
||||
if (section == 0) {
|
||||
return 2;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)tableView:(UITableView *)aTableView titleForFooterInSection:(NSInteger)section
|
||||
{
|
||||
if (section == [self numberOfSectionsInTableView:aTableView]-1) {
|
||||
// If we're using Basic authentication and the connection is not using SSL, we'll show the plain text message
|
||||
if ([[[self request] authenticationScheme] isEqualToString:(NSString *)kCFHTTPAuthenticationSchemeBasic] && ![[[[self request] url] scheme] isEqualToString:@"https"]) {
|
||||
return @"Password will be sent in the clear.";
|
||||
// We are using Digest, NTLM, or any scheme over SSL
|
||||
} else {
|
||||
return @"Password will be sent securely.";
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@synthesize request;
|
||||
@synthesize type;
|
||||
@synthesize tableView;
|
||||
@synthesize didEnableRotationNotifications;
|
||||
@synthesize presentingController;
|
||||
@end
|
||||
103
msext/Class/Common/ASIHttpRequest/ASICacheDelegate.h
Executable file
103
msext/Class/Common/ASIHttpRequest/ASICacheDelegate.h
Executable file
@@ -0,0 +1,103 @@
|
||||
//
|
||||
// ASICacheDelegate.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 01/05/2010.
|
||||
// Copyright 2010 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
@class ASIHTTPRequest;
|
||||
|
||||
// Cache policies control the behaviour of a cache and how requests use the cache
|
||||
// When setting a cache policy, you can use a combination of these values as a bitmask
|
||||
// For example: [request setCachePolicy:ASIAskServerIfModifiedCachePolicy|ASIFallbackToCacheIfLoadFailsCachePolicy|ASIDoNotWriteToCacheCachePolicy];
|
||||
// Note that some of the behaviours below are mutally exclusive - you cannot combine ASIAskServerIfModifiedWhenStaleCachePolicy and ASIAskServerIfModifiedCachePolicy, for example.
|
||||
typedef enum _ASICachePolicy {
|
||||
|
||||
// The default cache policy. When you set a request to use this, it will use the cache's defaultCachePolicy
|
||||
// ASIDownloadCache's default cache policy is 'ASIAskServerIfModifiedWhenStaleCachePolicy'
|
||||
ASIUseDefaultCachePolicy = 0,
|
||||
|
||||
// Tell the request not to read from the cache
|
||||
ASIDoNotReadFromCacheCachePolicy = 1,
|
||||
|
||||
// The the request not to write to the cache
|
||||
ASIDoNotWriteToCacheCachePolicy = 2,
|
||||
|
||||
// Ask the server if there is an updated version of this resource (using a conditional GET) ONLY when the cached data is stale
|
||||
ASIAskServerIfModifiedWhenStaleCachePolicy = 4,
|
||||
|
||||
// Always ask the server if there is an updated version of this resource (using a conditional GET)
|
||||
ASIAskServerIfModifiedCachePolicy = 8,
|
||||
|
||||
// If cached data exists, use it even if it is stale. This means requests will not talk to the server unless the resource they are requesting is not in the cache
|
||||
ASIOnlyLoadIfNotCachedCachePolicy = 16,
|
||||
|
||||
// If cached data exists, use it even if it is stale. If cached data does not exist, stop (will not set an error on the request)
|
||||
ASIDontLoadCachePolicy = 32,
|
||||
|
||||
// Specifies that cached data may be used if the request fails. If cached data is used, the request will succeed without error. Usually used in combination with other options above.
|
||||
ASIFallbackToCacheIfLoadFailsCachePolicy = 64
|
||||
} ASICachePolicy;
|
||||
|
||||
// Cache storage policies control whether cached data persists between application launches (ASICachePermanentlyCacheStoragePolicy) or not (ASICacheForSessionDurationCacheStoragePolicy)
|
||||
// Calling [ASIHTTPRequest clearSession] will remove any data stored using ASICacheForSessionDurationCacheStoragePolicy
|
||||
typedef enum _ASICacheStoragePolicy {
|
||||
ASICacheForSessionDurationCacheStoragePolicy = 0,
|
||||
ASICachePermanentlyCacheStoragePolicy = 1
|
||||
} ASICacheStoragePolicy;
|
||||
|
||||
|
||||
@protocol ASICacheDelegate <NSObject>
|
||||
|
||||
@required
|
||||
|
||||
// Should return the cache policy that will be used when requests have their cache policy set to ASIUseDefaultCachePolicy
|
||||
- (ASICachePolicy)defaultCachePolicy;
|
||||
|
||||
// Returns the date a cached response should expire on. Pass a non-zero max age to specify a custom date.
|
||||
- (NSDate *)expiryDateForRequest:(ASIHTTPRequest *)request maxAge:(NSTimeInterval)maxAge;
|
||||
|
||||
// Updates cached response headers with a new expiry date. Pass a non-zero max age to specify a custom date.
|
||||
- (void)updateExpiryForRequest:(ASIHTTPRequest *)request maxAge:(NSTimeInterval)maxAge;
|
||||
|
||||
// Looks at the request's cache policy and any cached headers to determine if the cache data is still valid
|
||||
- (BOOL)canUseCachedDataForRequest:(ASIHTTPRequest *)request;
|
||||
|
||||
// Removes cached data for a particular request
|
||||
- (void)removeCachedDataForRequest:(ASIHTTPRequest *)request;
|
||||
|
||||
// Should return YES if the cache considers its cached response current for the request
|
||||
// Should return NO is the data is not cached, or (for example) if the cached headers state the request should have expired
|
||||
- (BOOL)isCachedDataCurrentForRequest:(ASIHTTPRequest *)request;
|
||||
|
||||
// Should store the response for the passed request in the cache
|
||||
// When a non-zero maxAge is passed, it should be used as the expiry time for the cached response
|
||||
- (void)storeResponseForRequest:(ASIHTTPRequest *)request maxAge:(NSTimeInterval)maxAge;
|
||||
|
||||
// Removes cached data for a particular url
|
||||
- (void)removeCachedDataForURL:(NSURL *)url;
|
||||
|
||||
// Should return an NSDictionary of cached headers for the passed URL, if it is stored in the cache
|
||||
- (NSDictionary *)cachedResponseHeadersForURL:(NSURL *)url;
|
||||
|
||||
// Should return the cached body of a response for the passed URL, if it is stored in the cache
|
||||
- (NSData *)cachedResponseDataForURL:(NSURL *)url;
|
||||
|
||||
// Returns a path to the cached response data, if it exists
|
||||
- (NSString *)pathToCachedResponseDataForURL:(NSURL *)url;
|
||||
|
||||
// Returns a path to the cached response headers, if they url
|
||||
- (NSString *)pathToCachedResponseHeadersForURL:(NSURL *)url;
|
||||
|
||||
// Returns the location to use to store cached response headers for a particular request
|
||||
- (NSString *)pathToStoreCachedResponseHeadersForRequest:(ASIHTTPRequest *)request;
|
||||
|
||||
// Returns the location to use to store a cached response body for a particular request
|
||||
- (NSString *)pathToStoreCachedResponseDataForRequest:(ASIHTTPRequest *)request;
|
||||
|
||||
// Clear cached data stored for the passed storage policy
|
||||
- (void)clearCachedResponsesForStoragePolicy:(ASICacheStoragePolicy)cachePolicy;
|
||||
|
||||
@end
|
||||
42
msext/Class/Common/ASIHttpRequest/ASIDataCompressor.h
Executable file
42
msext/Class/Common/ASIHttpRequest/ASIDataCompressor.h
Executable file
@@ -0,0 +1,42 @@
|
||||
//
|
||||
// ASIDataCompressor.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 17/08/2010.
|
||||
// Copyright 2010 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
// This is a helper class used by ASIHTTPRequest to handle deflating (compressing) data in memory and on disk
|
||||
// You may also find it helpful if you need to deflate data and files yourself - see the class methods below
|
||||
// Most of the zlib stuff is based on the sample code by Mark Adler available at http://zlib.net
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <zlib.h>
|
||||
|
||||
@interface ASIDataCompressor : NSObject {
|
||||
BOOL streamReady;
|
||||
z_stream zStream;
|
||||
}
|
||||
|
||||
// Convenience constructor will call setupStream for you
|
||||
+ (id)compressor;
|
||||
|
||||
// Compress the passed chunk of data
|
||||
// Passing YES for shouldFinish will finalize the deflated data - you must pass YES when you are on the last chunk of data
|
||||
- (NSData *)compressBytes:(Bytef *)bytes length:(NSUInteger)length error:(NSError **)err shouldFinish:(BOOL)shouldFinish;
|
||||
|
||||
// Convenience method - pass it some data, and you'll get deflated data back
|
||||
+ (NSData *)compressData:(NSData*)uncompressedData error:(NSError **)err;
|
||||
|
||||
// Convenience method - pass it a file containing the data to compress in sourcePath, and it will write deflated data to destinationPath
|
||||
+ (BOOL)compressDataFromFile:(NSString *)sourcePath toFile:(NSString *)destinationPath error:(NSError **)err;
|
||||
|
||||
// Sets up zlib to handle the inflating. You only need to call this yourself if you aren't using the convenience constructor 'compressor'
|
||||
- (NSError *)setupStream;
|
||||
|
||||
// Tells zlib to clean up. You need to call this if you need to cancel deflating part way through
|
||||
// If deflating finishes or fails, this method will be called automatically
|
||||
- (NSError *)closeStream;
|
||||
|
||||
@property (assign, readonly) BOOL streamReady;
|
||||
@end
|
||||
219
msext/Class/Common/ASIHttpRequest/ASIDataCompressor.m
Executable file
219
msext/Class/Common/ASIHttpRequest/ASIDataCompressor.m
Executable file
@@ -0,0 +1,219 @@
|
||||
//
|
||||
// ASIDataCompressor.m
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 17/08/2010.
|
||||
// Copyright 2010 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ASIDataCompressor.h"
|
||||
#import "ASIHTTPRequest.h"
|
||||
|
||||
#define DATA_CHUNK_SIZE 262144 // Deal with gzipped data in 256KB chunks
|
||||
#define COMPRESSION_AMOUNT Z_DEFAULT_COMPRESSION
|
||||
|
||||
@interface ASIDataCompressor ()
|
||||
+ (NSError *)deflateErrorWithCode:(int)code;
|
||||
@end
|
||||
|
||||
@implementation ASIDataCompressor
|
||||
|
||||
+ (id)compressor
|
||||
{
|
||||
ASIDataCompressor *compressor = [[[self alloc] init] autorelease];
|
||||
[compressor setupStream];
|
||||
return compressor;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
if (streamReady) {
|
||||
[self closeStream];
|
||||
}
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (NSError *)setupStream
|
||||
{
|
||||
if (streamReady) {
|
||||
return nil;
|
||||
}
|
||||
// Setup the inflate stream
|
||||
zStream.zalloc = Z_NULL;
|
||||
zStream.zfree = Z_NULL;
|
||||
zStream.opaque = Z_NULL;
|
||||
zStream.avail_in = 0;
|
||||
zStream.next_in = 0;
|
||||
int status = deflateInit2(&zStream, COMPRESSION_AMOUNT, Z_DEFLATED, (15+16), 8, Z_DEFAULT_STRATEGY);
|
||||
if (status != Z_OK) {
|
||||
return [[self class] deflateErrorWithCode:status];
|
||||
}
|
||||
streamReady = YES;
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSError *)closeStream
|
||||
{
|
||||
if (!streamReady) {
|
||||
return nil;
|
||||
}
|
||||
// Close the deflate stream
|
||||
streamReady = NO;
|
||||
int status = deflateEnd(&zStream);
|
||||
if (status != Z_OK) {
|
||||
return [[self class] deflateErrorWithCode:status];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSData *)compressBytes:(Bytef *)bytes length:(NSUInteger)length error:(NSError **)err shouldFinish:(BOOL)shouldFinish
|
||||
{
|
||||
if (length == 0) return nil;
|
||||
|
||||
NSUInteger halfLength = length/2;
|
||||
|
||||
// We'll take a guess that the compressed data will fit in half the size of the original (ie the max to compress at once is half DATA_CHUNK_SIZE), if not, we'll increase it below
|
||||
NSMutableData *outputData = [NSMutableData dataWithLength:length/2];
|
||||
|
||||
int status;
|
||||
|
||||
zStream.next_in = bytes;
|
||||
zStream.avail_in = (unsigned int)length;
|
||||
zStream.avail_out = 0;
|
||||
|
||||
NSInteger bytesProcessedAlready = zStream.total_out;
|
||||
while (zStream.avail_out == 0) {
|
||||
|
||||
if (zStream.total_out-bytesProcessedAlready >= [outputData length]) {
|
||||
[outputData increaseLengthBy:halfLength];
|
||||
}
|
||||
|
||||
zStream.next_out = (Bytef*)[outputData mutableBytes] + zStream.total_out-bytesProcessedAlready;
|
||||
zStream.avail_out = (unsigned int)([outputData length] - (zStream.total_out-bytesProcessedAlready));
|
||||
status = deflate(&zStream, shouldFinish ? Z_FINISH : Z_NO_FLUSH);
|
||||
|
||||
if (status == Z_STREAM_END) {
|
||||
break;
|
||||
} else if (status != Z_OK) {
|
||||
if (err) {
|
||||
*err = [[self class] deflateErrorWithCode:status];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
// Set real length
|
||||
[outputData setLength: zStream.total_out-bytesProcessedAlready];
|
||||
return outputData;
|
||||
}
|
||||
|
||||
|
||||
+ (NSData *)compressData:(NSData*)uncompressedData error:(NSError **)err
|
||||
{
|
||||
NSError *theError = nil;
|
||||
NSData *outputData = [[ASIDataCompressor compressor] compressBytes:(Bytef *)[uncompressedData bytes] length:[uncompressedData length] error:&theError shouldFinish:YES];
|
||||
if (theError) {
|
||||
if (err) {
|
||||
*err = theError;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
return outputData;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+ (BOOL)compressDataFromFile:(NSString *)sourcePath toFile:(NSString *)destinationPath error:(NSError **)err
|
||||
{
|
||||
NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease];
|
||||
|
||||
// Create an empty file at the destination path
|
||||
if (![fileManager createFileAtPath:destinationPath contents:[NSData data] attributes:nil]) {
|
||||
if (err) {
|
||||
*err = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Compression of %@ failed because we were to create a file at %@",sourcePath,destinationPath],NSLocalizedDescriptionKey,nil]];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Ensure the source file exists
|
||||
if (![fileManager fileExistsAtPath:sourcePath]) {
|
||||
if (err) {
|
||||
*err = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Compression of %@ failed the file does not exist",sourcePath],NSLocalizedDescriptionKey,nil]];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
UInt8 inputData[DATA_CHUNK_SIZE];
|
||||
NSData *outputData;
|
||||
NSInteger readLength;
|
||||
NSError *theError = nil;
|
||||
|
||||
ASIDataCompressor *compressor = [ASIDataCompressor compressor];
|
||||
|
||||
NSInputStream *inputStream = [NSInputStream inputStreamWithFileAtPath:sourcePath];
|
||||
[inputStream open];
|
||||
NSOutputStream *outputStream = [NSOutputStream outputStreamToFileAtPath:destinationPath append:NO];
|
||||
[outputStream open];
|
||||
|
||||
while ([compressor streamReady]) {
|
||||
|
||||
// Read some data from the file
|
||||
readLength = [inputStream read:inputData maxLength:DATA_CHUNK_SIZE];
|
||||
|
||||
// Make sure nothing went wrong
|
||||
if ([inputStream streamStatus] == NSStreamEventErrorOccurred) {
|
||||
if (err) {
|
||||
*err = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Compression of %@ failed because we were unable to read from the source data file",sourcePath],NSLocalizedDescriptionKey,[inputStream streamError],NSUnderlyingErrorKey,nil]];
|
||||
}
|
||||
[compressor closeStream];
|
||||
return NO;
|
||||
}
|
||||
// Have we reached the end of the input data?
|
||||
if (!readLength) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Attempt to deflate the chunk of data
|
||||
outputData = [compressor compressBytes:inputData length:readLength error:&theError shouldFinish:readLength < DATA_CHUNK_SIZE ];
|
||||
if (theError) {
|
||||
if (err) {
|
||||
*err = theError;
|
||||
}
|
||||
[compressor closeStream];
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Write the deflated data out to the destination file
|
||||
[outputStream write:(const uint8_t *)[outputData bytes] maxLength:[outputData length]];
|
||||
|
||||
// Make sure nothing went wrong
|
||||
if ([inputStream streamStatus] == NSStreamEventErrorOccurred) {
|
||||
if (err) {
|
||||
*err = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Compression of %@ failed because we were unable to write to the destination data file at %@",sourcePath,destinationPath],NSLocalizedDescriptionKey,[outputStream streamError],NSUnderlyingErrorKey,nil]];
|
||||
}
|
||||
[compressor closeStream];
|
||||
return NO;
|
||||
}
|
||||
|
||||
}
|
||||
[inputStream close];
|
||||
[outputStream close];
|
||||
|
||||
NSError *error = [compressor closeStream];
|
||||
if (error) {
|
||||
if (err) {
|
||||
*err = error;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
+ (NSError *)deflateErrorWithCode:(int)code
|
||||
{
|
||||
return [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Compression of data failed with code %d",code],NSLocalizedDescriptionKey,nil]];
|
||||
}
|
||||
|
||||
@synthesize streamReady;
|
||||
@end
|
||||
41
msext/Class/Common/ASIHttpRequest/ASIDataDecompressor.h
Executable file
41
msext/Class/Common/ASIHttpRequest/ASIDataDecompressor.h
Executable file
@@ -0,0 +1,41 @@
|
||||
//
|
||||
// ASIDataDecompressor.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 17/08/2010.
|
||||
// Copyright 2010 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
// This is a helper class used by ASIHTTPRequest to handle inflating (decompressing) data in memory and on disk
|
||||
// You may also find it helpful if you need to inflate data and files yourself - see the class methods below
|
||||
// Most of the zlib stuff is based on the sample code by Mark Adler available at http://zlib.net
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <zlib.h>
|
||||
|
||||
@interface ASIDataDecompressor : NSObject {
|
||||
BOOL streamReady;
|
||||
z_stream zStream;
|
||||
}
|
||||
|
||||
// Convenience constructor will call setupStream for you
|
||||
+ (id)decompressor;
|
||||
|
||||
// Uncompress the passed chunk of data
|
||||
- (NSData *)uncompressBytes:(Bytef *)bytes length:(NSUInteger)length error:(NSError **)err;
|
||||
|
||||
// Convenience method - pass it some deflated data, and you'll get inflated data back
|
||||
+ (NSData *)uncompressData:(NSData*)compressedData error:(NSError **)err;
|
||||
|
||||
// Convenience method - pass it a file containing deflated data in sourcePath, and it will write inflated data to destinationPath
|
||||
+ (BOOL)uncompressDataFromFile:(NSString *)sourcePath toFile:(NSString *)destinationPath error:(NSError **)err;
|
||||
|
||||
// Sets up zlib to handle the inflating. You only need to call this yourself if you aren't using the convenience constructor 'decompressor'
|
||||
- (NSError *)setupStream;
|
||||
|
||||
// Tells zlib to clean up. You need to call this if you need to cancel inflating part way through
|
||||
// If inflating finishes or fails, this method will be called automatically
|
||||
- (NSError *)closeStream;
|
||||
|
||||
@property (assign, readonly) BOOL streamReady;
|
||||
@end
|
||||
218
msext/Class/Common/ASIHttpRequest/ASIDataDecompressor.m
Executable file
218
msext/Class/Common/ASIHttpRequest/ASIDataDecompressor.m
Executable file
@@ -0,0 +1,218 @@
|
||||
//
|
||||
// ASIDataDecompressor.m
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 17/08/2010.
|
||||
// Copyright 2010 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ASIDataDecompressor.h"
|
||||
#import "ASIHTTPRequest.h"
|
||||
|
||||
#define DATA_CHUNK_SIZE 262144 // Deal with gzipped data in 256KB chunks
|
||||
|
||||
@interface ASIDataDecompressor ()
|
||||
+ (NSError *)inflateErrorWithCode:(int)code;
|
||||
@end;
|
||||
|
||||
@implementation ASIDataDecompressor
|
||||
|
||||
+ (id)decompressor
|
||||
{
|
||||
ASIDataDecompressor *decompressor = [[[self alloc] init] autorelease];
|
||||
[decompressor setupStream];
|
||||
return decompressor;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
if (streamReady) {
|
||||
[self closeStream];
|
||||
}
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (NSError *)setupStream
|
||||
{
|
||||
if (streamReady) {
|
||||
return nil;
|
||||
}
|
||||
// Setup the inflate stream
|
||||
zStream.zalloc = Z_NULL;
|
||||
zStream.zfree = Z_NULL;
|
||||
zStream.opaque = Z_NULL;
|
||||
zStream.avail_in = 0;
|
||||
zStream.next_in = 0;
|
||||
int status = inflateInit2(&zStream, (15+32));
|
||||
if (status != Z_OK) {
|
||||
return [[self class] inflateErrorWithCode:status];
|
||||
}
|
||||
streamReady = YES;
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSError *)closeStream
|
||||
{
|
||||
if (!streamReady) {
|
||||
return nil;
|
||||
}
|
||||
// Close the inflate stream
|
||||
streamReady = NO;
|
||||
int status = inflateEnd(&zStream);
|
||||
if (status != Z_OK) {
|
||||
return [[self class] inflateErrorWithCode:status];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSData *)uncompressBytes:(Bytef *)bytes length:(NSUInteger)length error:(NSError **)err
|
||||
{
|
||||
if (length == 0) return nil;
|
||||
|
||||
NSUInteger halfLength = length/2;
|
||||
NSMutableData *outputData = [NSMutableData dataWithLength:length+halfLength];
|
||||
|
||||
int status;
|
||||
|
||||
zStream.next_in = bytes;
|
||||
zStream.avail_in = (unsigned int)length;
|
||||
zStream.avail_out = 0;
|
||||
|
||||
NSInteger bytesProcessedAlready = zStream.total_out;
|
||||
while (zStream.avail_in != 0) {
|
||||
|
||||
if (zStream.total_out-bytesProcessedAlready >= [outputData length]) {
|
||||
[outputData increaseLengthBy:halfLength];
|
||||
}
|
||||
|
||||
zStream.next_out = (Bytef*)[outputData mutableBytes] + zStream.total_out-bytesProcessedAlready;
|
||||
zStream.avail_out = (unsigned int)([outputData length] - (zStream.total_out-bytesProcessedAlready));
|
||||
|
||||
status = inflate(&zStream, Z_NO_FLUSH);
|
||||
|
||||
if (status == Z_STREAM_END) {
|
||||
break;
|
||||
} else if (status != Z_OK) {
|
||||
if (err) {
|
||||
*err = [[self class] inflateErrorWithCode:status];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
// Set real length
|
||||
[outputData setLength: zStream.total_out-bytesProcessedAlready];
|
||||
return outputData;
|
||||
}
|
||||
|
||||
|
||||
+ (NSData *)uncompressData:(NSData*)compressedData error:(NSError **)err
|
||||
{
|
||||
NSError *theError = nil;
|
||||
NSData *outputData = [[ASIDataDecompressor decompressor] uncompressBytes:(Bytef *)[compressedData bytes] length:[compressedData length] error:&theError];
|
||||
if (theError) {
|
||||
if (err) {
|
||||
*err = theError;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
return outputData;
|
||||
}
|
||||
|
||||
+ (BOOL)uncompressDataFromFile:(NSString *)sourcePath toFile:(NSString *)destinationPath error:(NSError **)err
|
||||
{
|
||||
NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease];
|
||||
|
||||
// Create an empty file at the destination path
|
||||
if (![fileManager createFileAtPath:destinationPath contents:[NSData data] attributes:nil]) {
|
||||
if (err) {
|
||||
*err = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Decompression of %@ failed because we were to create a file at %@",sourcePath,destinationPath],NSLocalizedDescriptionKey,nil]];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Ensure the source file exists
|
||||
if (![fileManager fileExistsAtPath:sourcePath]) {
|
||||
if (err) {
|
||||
*err = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Decompression of %@ failed the file does not exist",sourcePath],NSLocalizedDescriptionKey,nil]];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
UInt8 inputData[DATA_CHUNK_SIZE];
|
||||
NSData *outputData;
|
||||
NSInteger readLength;
|
||||
NSError *theError = nil;
|
||||
|
||||
|
||||
ASIDataDecompressor *decompressor = [ASIDataDecompressor decompressor];
|
||||
|
||||
NSInputStream *inputStream = [NSInputStream inputStreamWithFileAtPath:sourcePath];
|
||||
[inputStream open];
|
||||
NSOutputStream *outputStream = [NSOutputStream outputStreamToFileAtPath:destinationPath append:NO];
|
||||
[outputStream open];
|
||||
|
||||
while ([decompressor streamReady]) {
|
||||
|
||||
// Read some data from the file
|
||||
readLength = [inputStream read:inputData maxLength:DATA_CHUNK_SIZE];
|
||||
|
||||
// Make sure nothing went wrong
|
||||
if ([inputStream streamStatus] == NSStreamEventErrorOccurred) {
|
||||
if (err) {
|
||||
*err = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Decompression of %@ failed because we were unable to read from the source data file",sourcePath],NSLocalizedDescriptionKey,[inputStream streamError],NSUnderlyingErrorKey,nil]];
|
||||
}
|
||||
[decompressor closeStream];
|
||||
return NO;
|
||||
}
|
||||
// Have we reached the end of the input data?
|
||||
if (!readLength) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Attempt to inflate the chunk of data
|
||||
outputData = [decompressor uncompressBytes:inputData length:readLength error:&theError];
|
||||
if (theError) {
|
||||
if (err) {
|
||||
*err = theError;
|
||||
}
|
||||
[decompressor closeStream];
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Write the inflated data out to the destination file
|
||||
[outputStream write:(Bytef*)[outputData bytes] maxLength:[outputData length]];
|
||||
|
||||
// Make sure nothing went wrong
|
||||
if ([inputStream streamStatus] == NSStreamEventErrorOccurred) {
|
||||
if (err) {
|
||||
*err = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Decompression of %@ failed because we were unable to write to the destination data file at %@",sourcePath,destinationPath],NSLocalizedDescriptionKey,[outputStream streamError],NSUnderlyingErrorKey,nil]];
|
||||
}
|
||||
[decompressor closeStream];
|
||||
return NO;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[inputStream close];
|
||||
[outputStream close];
|
||||
|
||||
NSError *error = [decompressor closeStream];
|
||||
if (error) {
|
||||
if (err) {
|
||||
*err = error;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
+ (NSError *)inflateErrorWithCode:(int)code
|
||||
{
|
||||
return [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Decompression of data failed with code %d",code],NSLocalizedDescriptionKey,nil]];
|
||||
}
|
||||
|
||||
@synthesize streamReady;
|
||||
@end
|
||||
46
msext/Class/Common/ASIHttpRequest/ASIDownloadCache.h
Executable file
46
msext/Class/Common/ASIHttpRequest/ASIDownloadCache.h
Executable file
@@ -0,0 +1,46 @@
|
||||
//
|
||||
// ASIDownloadCache.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 01/05/2010.
|
||||
// Copyright 2010 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "ASICacheDelegate.h"
|
||||
|
||||
@interface ASIDownloadCache : NSObject <ASICacheDelegate> {
|
||||
|
||||
// The default cache policy for this cache
|
||||
// Requests that store data in the cache will use this cache policy if their cache policy is set to ASIUseDefaultCachePolicy
|
||||
// Defaults to ASIAskServerIfModifiedWhenStaleCachePolicy
|
||||
ASICachePolicy defaultCachePolicy;
|
||||
|
||||
// The directory in which cached data will be stored
|
||||
// Defaults to a directory called 'ASIHTTPRequestCache' in the temporary directory
|
||||
NSString *storagePath;
|
||||
|
||||
// Mediates access to the cache
|
||||
NSRecursiveLock *accessLock;
|
||||
|
||||
// When YES, the cache will look for cache-control / pragma: no-cache headers, and won't reuse store responses if it finds them
|
||||
BOOL shouldRespectCacheControlHeaders;
|
||||
}
|
||||
|
||||
// Returns a static instance of an ASIDownloadCache
|
||||
// In most circumstances, it will make sense to use this as a global cache, rather than creating your own cache
|
||||
// To make ASIHTTPRequests use it automatically, use [ASIHTTPRequest setDefaultCache:[ASIDownloadCache sharedCache]];
|
||||
+ (id)sharedCache;
|
||||
|
||||
// A helper function that determines if the server has requested data should not be cached by looking at the request's response headers
|
||||
+ (BOOL)serverAllowsResponseCachingForRequest:(ASIHTTPRequest *)request;
|
||||
|
||||
// A list of file extensions that we know won't be readable by a webview when accessed locally
|
||||
// If we're asking for a path to cache a particular url and it has one of these extensions, we change it to '.html'
|
||||
+ (NSArray *)fileExtensionsToHandleAsHTML;
|
||||
|
||||
@property (assign, nonatomic) ASICachePolicy defaultCachePolicy;
|
||||
@property (retain, nonatomic) NSString *storagePath;
|
||||
@property (retain) NSRecursiveLock *accessLock;
|
||||
@property (assign) BOOL shouldRespectCacheControlHeaders;
|
||||
@end
|
||||
514
msext/Class/Common/ASIHttpRequest/ASIDownloadCache.m
Executable file
514
msext/Class/Common/ASIHttpRequest/ASIDownloadCache.m
Executable file
@@ -0,0 +1,514 @@
|
||||
//
|
||||
// ASIDownloadCache.m
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 01/05/2010.
|
||||
// Copyright 2010 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ASIDownloadCache.h"
|
||||
#import "ASIHTTPRequest.h"
|
||||
#import <CommonCrypto/CommonHMAC.h>
|
||||
|
||||
static ASIDownloadCache *sharedCache = nil;
|
||||
|
||||
static NSString *sessionCacheFolder = @"SessionStore";
|
||||
static NSString *permanentCacheFolder = @"PermanentStore";
|
||||
static NSArray *fileExtensionsToHandleAsHTML = nil;
|
||||
|
||||
@interface ASIDownloadCache ()
|
||||
+ (NSString *)keyForURL:(NSURL *)url;
|
||||
- (NSString *)pathToFile:(NSString *)file;
|
||||
@end
|
||||
|
||||
@implementation ASIDownloadCache
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
if (self == [ASIDownloadCache class]) {
|
||||
// Obviously this is not an exhaustive list, but hopefully these are the most commonly used and this will 'just work' for the widest range of people
|
||||
// I imagine many web developers probably use url rewriting anyway
|
||||
fileExtensionsToHandleAsHTML = [[NSArray alloc] initWithObjects:@"asp",@"aspx",@"jsp",@"php",@"rb",@"py",@"pl",@"cgi", nil];
|
||||
}
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
[self setShouldRespectCacheControlHeaders:YES];
|
||||
[self setDefaultCachePolicy:ASIUseDefaultCachePolicy];
|
||||
[self setAccessLock:[[[NSRecursiveLock alloc] init] autorelease]];
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (id)sharedCache
|
||||
{
|
||||
if (!sharedCache) {
|
||||
@synchronized(self) {
|
||||
if (!sharedCache) {
|
||||
sharedCache = [[self alloc] init];
|
||||
[sharedCache setStoragePath:[[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:@"ASIHTTPRequestCache"]];
|
||||
}
|
||||
}
|
||||
}
|
||||
return sharedCache;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[storagePath release];
|
||||
[accessLock release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (NSString *)storagePath
|
||||
{
|
||||
[[self accessLock] lock];
|
||||
NSString *p = [[storagePath retain] autorelease];
|
||||
[[self accessLock] unlock];
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
- (void)setStoragePath:(NSString *)path
|
||||
{
|
||||
[[self accessLock] lock];
|
||||
[self clearCachedResponsesForStoragePolicy:ASICacheForSessionDurationCacheStoragePolicy];
|
||||
[storagePath release];
|
||||
storagePath = [path retain];
|
||||
|
||||
NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease];
|
||||
|
||||
BOOL isDirectory = NO;
|
||||
NSArray *directories = [NSArray arrayWithObjects:path,[path stringByAppendingPathComponent:sessionCacheFolder],[path stringByAppendingPathComponent:permanentCacheFolder],nil];
|
||||
for (NSString *directory in directories) {
|
||||
BOOL exists = [fileManager fileExistsAtPath:directory isDirectory:&isDirectory];
|
||||
if (exists && !isDirectory) {
|
||||
[[self accessLock] unlock];
|
||||
[NSException raise:@"FileExistsAtCachePath" format:@"Cannot create a directory for the cache at '%@', because a file already exists",directory];
|
||||
} else if (!exists) {
|
||||
[fileManager createDirectoryAtPath:directory withIntermediateDirectories:NO attributes:nil error:nil];
|
||||
if (![fileManager fileExistsAtPath:directory]) {
|
||||
[[self accessLock] unlock];
|
||||
[NSException raise:@"FailedToCreateCacheDirectory" format:@"Failed to create a directory for the cache at '%@'",directory];
|
||||
}
|
||||
}
|
||||
}
|
||||
[self clearCachedResponsesForStoragePolicy:ASICacheForSessionDurationCacheStoragePolicy];
|
||||
[[self accessLock] unlock];
|
||||
}
|
||||
|
||||
- (void)updateExpiryForRequest:(ASIHTTPRequest *)request maxAge:(NSTimeInterval)maxAge
|
||||
{
|
||||
NSString *headerPath = [self pathToStoreCachedResponseHeadersForRequest:request];
|
||||
NSMutableDictionary *cachedHeaders = [NSMutableDictionary dictionaryWithContentsOfFile:headerPath];
|
||||
if (!cachedHeaders) {
|
||||
return;
|
||||
}
|
||||
NSDate *expires = [self expiryDateForRequest:request maxAge:maxAge];
|
||||
if (!expires) {
|
||||
return;
|
||||
}
|
||||
[cachedHeaders setObject:[NSNumber numberWithDouble:[expires timeIntervalSince1970]] forKey:@"X-ASIHTTPRequest-Expires"];
|
||||
[cachedHeaders writeToFile:headerPath atomically:NO];
|
||||
}
|
||||
|
||||
- (NSDate *)expiryDateForRequest:(ASIHTTPRequest *)request maxAge:(NSTimeInterval)maxAge
|
||||
{
|
||||
return [ASIHTTPRequest expiryDateForRequest:request maxAge:maxAge];
|
||||
}
|
||||
|
||||
- (void)storeResponseForRequest:(ASIHTTPRequest *)request maxAge:(NSTimeInterval)maxAge
|
||||
{
|
||||
[[self accessLock] lock];
|
||||
|
||||
if ([request error] || ![request responseHeaders] || ([request cachePolicy] & ASIDoNotWriteToCacheCachePolicy)) {
|
||||
[[self accessLock] unlock];
|
||||
return;
|
||||
}
|
||||
|
||||
// We only cache 200/OK or redirect reponses (redirect responses are cached so the cache works better with no internet connection)
|
||||
int responseCode = [request responseStatusCode];
|
||||
if (responseCode != 200 && responseCode != 301 && responseCode != 302 && responseCode != 303 && responseCode != 307) {
|
||||
[[self accessLock] unlock];
|
||||
return;
|
||||
}
|
||||
|
||||
if ([self shouldRespectCacheControlHeaders] && ![[self class] serverAllowsResponseCachingForRequest:request]) {
|
||||
[[self accessLock] unlock];
|
||||
return;
|
||||
}
|
||||
|
||||
NSString *headerPath = [self pathToStoreCachedResponseHeadersForRequest:request];
|
||||
NSString *dataPath = [self pathToStoreCachedResponseDataForRequest:request];
|
||||
|
||||
NSMutableDictionary *responseHeaders = [NSMutableDictionary dictionaryWithDictionary:[request responseHeaders]];
|
||||
if ([request isResponseCompressed]) {
|
||||
[responseHeaders removeObjectForKey:@"Content-Encoding"];
|
||||
}
|
||||
|
||||
// Create a special 'X-ASIHTTPRequest-Expires' header
|
||||
// This is what we use for deciding if cached data is current, rather than parsing the expires / max-age headers individually each time
|
||||
// We store this as a timestamp to make reading it easier as NSDateFormatter is quite expensive
|
||||
|
||||
NSDate *expires = [self expiryDateForRequest:request maxAge:maxAge];
|
||||
if (expires) {
|
||||
[responseHeaders setObject:[NSNumber numberWithDouble:[expires timeIntervalSince1970]] forKey:@"X-ASIHTTPRequest-Expires"];
|
||||
}
|
||||
|
||||
// Store the response code in a custom header so we can reuse it later
|
||||
|
||||
// We'll change 304/Not Modified to 200/OK because this is likely to be us updating the cached headers with a conditional GET
|
||||
int statusCode = [request responseStatusCode];
|
||||
if (statusCode == 304) {
|
||||
statusCode = 200;
|
||||
}
|
||||
[responseHeaders setObject:[NSNumber numberWithInt:statusCode] forKey:@"X-ASIHTTPRequest-Response-Status-Code"];
|
||||
|
||||
[responseHeaders writeToFile:headerPath atomically:NO];
|
||||
|
||||
if ([request responseData]) {
|
||||
[[request responseData] writeToFile:dataPath atomically:NO];
|
||||
} else if ([request downloadDestinationPath] && ![[request downloadDestinationPath] isEqualToString:dataPath]) {
|
||||
NSError *error = nil;
|
||||
NSFileManager* manager = [[NSFileManager alloc] init];
|
||||
if ([manager fileExistsAtPath:dataPath]) {
|
||||
[manager removeItemAtPath:dataPath error:&error];
|
||||
}
|
||||
[manager copyItemAtPath:[request downloadDestinationPath] toPath:dataPath error:&error];
|
||||
[manager release];
|
||||
}
|
||||
[[self accessLock] unlock];
|
||||
}
|
||||
|
||||
- (NSDictionary *)cachedResponseHeadersForURL:(NSURL *)url
|
||||
{
|
||||
NSString *path = [self pathToCachedResponseHeadersForURL:url];
|
||||
if (path) {
|
||||
return [NSDictionary dictionaryWithContentsOfFile:path];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSData *)cachedResponseDataForURL:(NSURL *)url
|
||||
{
|
||||
NSString *path = [self pathToCachedResponseDataForURL:url];
|
||||
if (path) {
|
||||
return [NSData dataWithContentsOfFile:path];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSString *)pathToCachedResponseDataForURL:(NSURL *)url
|
||||
{
|
||||
// Grab the file extension, if there is one. We do this so we can save the cached response with the same file extension - this is important if you want to display locally cached data in a web view
|
||||
NSString *extension = [[url path] pathExtension];
|
||||
|
||||
// If the url doesn't have an extension, we'll add one so a webview can read it when locally cached
|
||||
// If the url has the extension of a common web scripting language, we'll change the extension on the cached path to html for the same reason
|
||||
if (![extension length] || [[[self class] fileExtensionsToHandleAsHTML] containsObject:[extension lowercaseString]]) {
|
||||
extension = @"html";
|
||||
}
|
||||
return [self pathToFile:[[[self class] keyForURL:url] stringByAppendingPathExtension:extension]];
|
||||
}
|
||||
|
||||
+ (NSArray *)fileExtensionsToHandleAsHTML
|
||||
{
|
||||
return fileExtensionsToHandleAsHTML;
|
||||
}
|
||||
|
||||
|
||||
- (NSString *)pathToCachedResponseHeadersForURL:(NSURL *)url
|
||||
{
|
||||
return [self pathToFile:[[[self class] keyForURL:url] stringByAppendingPathExtension:@"cachedheaders"]];
|
||||
}
|
||||
|
||||
- (NSString *)pathToFile:(NSString *)file
|
||||
{
|
||||
[[self accessLock] lock];
|
||||
if (![self storagePath]) {
|
||||
[[self accessLock] unlock];
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease];
|
||||
|
||||
// Look in the session store
|
||||
NSString *dataPath = [[[self storagePath] stringByAppendingPathComponent:sessionCacheFolder] stringByAppendingPathComponent:file];
|
||||
if ([fileManager fileExistsAtPath:dataPath]) {
|
||||
[[self accessLock] unlock];
|
||||
return dataPath;
|
||||
}
|
||||
// Look in the permanent store
|
||||
dataPath = [[[self storagePath] stringByAppendingPathComponent:permanentCacheFolder] stringByAppendingPathComponent:file];
|
||||
if ([fileManager fileExistsAtPath:dataPath]) {
|
||||
[[self accessLock] unlock];
|
||||
return dataPath;
|
||||
}
|
||||
[[self accessLock] unlock];
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
- (NSString *)pathToStoreCachedResponseDataForRequest:(ASIHTTPRequest *)request
|
||||
{
|
||||
[[self accessLock] lock];
|
||||
if (![self storagePath]) {
|
||||
[[self accessLock] unlock];
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSString *path = [[self storagePath] stringByAppendingPathComponent:([request cacheStoragePolicy] == ASICacheForSessionDurationCacheStoragePolicy ? sessionCacheFolder : permanentCacheFolder)];
|
||||
|
||||
// Grab the file extension, if there is one. We do this so we can save the cached response with the same file extension - this is important if you want to display locally cached data in a web view
|
||||
NSString *extension = [[[request url] path] pathExtension];
|
||||
|
||||
// If the url doesn't have an extension, we'll add one so a webview can read it when locally cached
|
||||
// If the url has the extension of a common web scripting language, we'll change the extension on the cached path to html for the same reason
|
||||
if (![extension length] || [[[self class] fileExtensionsToHandleAsHTML] containsObject:[extension lowercaseString]]) {
|
||||
extension = @"html";
|
||||
}
|
||||
path = [path stringByAppendingPathComponent:[[[self class] keyForURL:[request url]] stringByAppendingPathExtension:extension]];
|
||||
[[self accessLock] unlock];
|
||||
return path;
|
||||
}
|
||||
|
||||
- (NSString *)pathToStoreCachedResponseHeadersForRequest:(ASIHTTPRequest *)request
|
||||
{
|
||||
[[self accessLock] lock];
|
||||
if (![self storagePath]) {
|
||||
[[self accessLock] unlock];
|
||||
return nil;
|
||||
}
|
||||
NSString *path = [[self storagePath] stringByAppendingPathComponent:([request cacheStoragePolicy] == ASICacheForSessionDurationCacheStoragePolicy ? sessionCacheFolder : permanentCacheFolder)];
|
||||
path = [path stringByAppendingPathComponent:[[[self class] keyForURL:[request url]] stringByAppendingPathExtension:@"cachedheaders"]];
|
||||
[[self accessLock] unlock];
|
||||
return path;
|
||||
}
|
||||
|
||||
- (void)removeCachedDataForURL:(NSURL *)url
|
||||
{
|
||||
[[self accessLock] lock];
|
||||
if (![self storagePath]) {
|
||||
[[self accessLock] unlock];
|
||||
return;
|
||||
}
|
||||
NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease];
|
||||
|
||||
NSString *path = [self pathToCachedResponseHeadersForURL:url];
|
||||
if (path) {
|
||||
[fileManager removeItemAtPath:path error:NULL];
|
||||
}
|
||||
|
||||
path = [self pathToCachedResponseDataForURL:url];
|
||||
if (path) {
|
||||
[fileManager removeItemAtPath:path error:NULL];
|
||||
}
|
||||
[[self accessLock] unlock];
|
||||
}
|
||||
|
||||
- (void)removeCachedDataForRequest:(ASIHTTPRequest *)request
|
||||
{
|
||||
[self removeCachedDataForURL:[request url]];
|
||||
}
|
||||
|
||||
- (BOOL)isCachedDataCurrentForRequest:(ASIHTTPRequest *)request
|
||||
{
|
||||
[[self accessLock] lock];
|
||||
if (![self storagePath]) {
|
||||
[[self accessLock] unlock];
|
||||
return NO;
|
||||
}
|
||||
NSDictionary *cachedHeaders = [self cachedResponseHeadersForURL:[request url]];
|
||||
if (!cachedHeaders) {
|
||||
[[self accessLock] unlock];
|
||||
return NO;
|
||||
}
|
||||
NSString *dataPath = [self pathToCachedResponseDataForURL:[request url]];
|
||||
if (!dataPath) {
|
||||
[[self accessLock] unlock];
|
||||
return NO;
|
||||
}
|
||||
|
||||
// New content is not different
|
||||
if ([request responseStatusCode] == 304) {
|
||||
[[self accessLock] unlock];
|
||||
return YES;
|
||||
}
|
||||
|
||||
// If we already have response headers for this request, check to see if the new content is different
|
||||
// We check [request complete] so that we don't end up comparing response headers from a redirection with these
|
||||
if ([request responseHeaders] && [request complete]) {
|
||||
|
||||
// If the Etag or Last-Modified date are different from the one we have, we'll have to fetch this resource again
|
||||
NSArray *headersToCompare = [NSArray arrayWithObjects:@"Etag",@"Last-Modified",nil];
|
||||
for (NSString *header in headersToCompare) {
|
||||
if (![[[request responseHeaders] objectForKey:header] isEqualToString:[cachedHeaders objectForKey:header]]) {
|
||||
[[self accessLock] unlock];
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ([self shouldRespectCacheControlHeaders]) {
|
||||
|
||||
// Look for X-ASIHTTPRequest-Expires header to see if the content is out of date
|
||||
NSNumber *expires = [cachedHeaders objectForKey:@"X-ASIHTTPRequest-Expires"];
|
||||
if (expires) {
|
||||
if ([[NSDate dateWithTimeIntervalSince1970:[expires doubleValue]] timeIntervalSinceNow] >= 0) {
|
||||
[[self accessLock] unlock];
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
// No explicit expiration time sent by the server
|
||||
[[self accessLock] unlock];
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
||||
[[self accessLock] unlock];
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (ASICachePolicy)defaultCachePolicy
|
||||
{
|
||||
[[self accessLock] lock];
|
||||
ASICachePolicy cp = defaultCachePolicy;
|
||||
[[self accessLock] unlock];
|
||||
return cp;
|
||||
}
|
||||
|
||||
|
||||
- (void)setDefaultCachePolicy:(ASICachePolicy)cachePolicy
|
||||
{
|
||||
[[self accessLock] lock];
|
||||
if (!cachePolicy) {
|
||||
defaultCachePolicy = ASIAskServerIfModifiedWhenStaleCachePolicy;
|
||||
} else {
|
||||
defaultCachePolicy = cachePolicy;
|
||||
}
|
||||
[[self accessLock] unlock];
|
||||
}
|
||||
|
||||
- (void)clearCachedResponsesForStoragePolicy:(ASICacheStoragePolicy)storagePolicy
|
||||
{
|
||||
[[self accessLock] lock];
|
||||
if (![self storagePath]) {
|
||||
[[self accessLock] unlock];
|
||||
return;
|
||||
}
|
||||
NSString *path = [[self storagePath] stringByAppendingPathComponent:(storagePolicy == ASICacheForSessionDurationCacheStoragePolicy ? sessionCacheFolder : permanentCacheFolder)];
|
||||
|
||||
NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease];
|
||||
|
||||
BOOL isDirectory = NO;
|
||||
BOOL exists = [fileManager fileExistsAtPath:path isDirectory:&isDirectory];
|
||||
if (!exists || !isDirectory) {
|
||||
[[self accessLock] unlock];
|
||||
return;
|
||||
}
|
||||
NSError *error = nil;
|
||||
NSArray *cacheFiles = [fileManager contentsOfDirectoryAtPath:path error:&error];
|
||||
if (error) {
|
||||
[[self accessLock] unlock];
|
||||
[NSException raise:@"FailedToTraverseCacheDirectory" format:@"Listing cache directory failed at path '%@'",path];
|
||||
}
|
||||
for (NSString *file in cacheFiles) {
|
||||
[fileManager removeItemAtPath:[path stringByAppendingPathComponent:file] error:&error];
|
||||
if (error) {
|
||||
[[self accessLock] unlock];
|
||||
[NSException raise:@"FailedToRemoveCacheFile" format:@"Failed to remove cached data at path '%@'",path];
|
||||
}
|
||||
}
|
||||
[[self accessLock] unlock];
|
||||
}
|
||||
|
||||
+ (BOOL)serverAllowsResponseCachingForRequest:(ASIHTTPRequest *)request
|
||||
{
|
||||
NSString *cacheControl = [[[request responseHeaders] objectForKey:@"Cache-Control"] lowercaseString];
|
||||
if (cacheControl) {
|
||||
if ([cacheControl isEqualToString:@"no-cache"] || [cacheControl isEqualToString:@"no-store"]) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
NSString *pragma = [[[request responseHeaders] objectForKey:@"Pragma"] lowercaseString];
|
||||
if (pragma) {
|
||||
if ([pragma isEqualToString:@"no-cache"]) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
+ (NSString *)keyForURL:(NSURL *)url
|
||||
{
|
||||
NSString *urlString = [url absoluteString];
|
||||
if ([urlString length] == 0) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
// Strip trailing slashes so http://allseeing-i.com/ASIHTTPRequest/ is cached the same as http://allseeing-i.com/ASIHTTPRequest
|
||||
if ([[urlString substringFromIndex:[urlString length]-1] isEqualToString:@"/"]) {
|
||||
urlString = [urlString substringToIndex:[urlString length]-1];
|
||||
}
|
||||
|
||||
// Borrowed from: http://stackoverflow.com/questions/652300/using-md5-hash-on-a-string-in-cocoa
|
||||
const char *cStr = [urlString UTF8String];
|
||||
unsigned char result[16];
|
||||
CC_MD5(cStr, (CC_LONG)strlen(cStr), result);
|
||||
return [NSString stringWithFormat:@"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",result[0], result[1], result[2], result[3], result[4], result[5], result[6], result[7],result[8], result[9], result[10], result[11],result[12], result[13], result[14], result[15]];
|
||||
}
|
||||
|
||||
- (BOOL)canUseCachedDataForRequest:(ASIHTTPRequest *)request
|
||||
{
|
||||
// Ensure the request is allowed to read from the cache
|
||||
if ([request cachePolicy] & ASIDoNotReadFromCacheCachePolicy) {
|
||||
return NO;
|
||||
|
||||
// If we don't want to load the request whatever happens, always pretend we have cached data even if we don't
|
||||
} else if ([request cachePolicy] & ASIDontLoadCachePolicy) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
NSDictionary *headers = [self cachedResponseHeadersForURL:[request url]];
|
||||
if (!headers) {
|
||||
return NO;
|
||||
}
|
||||
NSString *dataPath = [self pathToCachedResponseDataForURL:[request url]];
|
||||
if (!dataPath) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
// If we get here, we have cached data
|
||||
|
||||
// If we have cached data, we can use it
|
||||
if ([request cachePolicy] & ASIOnlyLoadIfNotCachedCachePolicy) {
|
||||
return YES;
|
||||
|
||||
// If we want to fallback to the cache after an error
|
||||
} else if ([request complete] && [request cachePolicy] & ASIFallbackToCacheIfLoadFailsCachePolicy) {
|
||||
return YES;
|
||||
|
||||
// If we have cached data that is current, we can use it
|
||||
} else if ([request cachePolicy] & ASIAskServerIfModifiedWhenStaleCachePolicy) {
|
||||
if ([self isCachedDataCurrentForRequest:request]) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
// If we've got headers from a conditional GET and the cached data is still current, we can use it
|
||||
} else if ([request cachePolicy] & ASIAskServerIfModifiedCachePolicy) {
|
||||
if (![request responseHeaders]) {
|
||||
return NO;
|
||||
} else if ([self isCachedDataCurrentForRequest:request]) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
@synthesize storagePath;
|
||||
@synthesize defaultCachePolicy;
|
||||
@synthesize accessLock;
|
||||
@synthesize shouldRespectCacheControlHeaders;
|
||||
@end
|
||||
76
msext/Class/Common/ASIHttpRequest/ASIFormDataRequest.h
Executable file
76
msext/Class/Common/ASIHttpRequest/ASIFormDataRequest.h
Executable file
@@ -0,0 +1,76 @@
|
||||
//
|
||||
// ASIFormDataRequest.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 07/11/2008.
|
||||
// Copyright 2008-2009 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "ASIHTTPRequest.h"
|
||||
#import "ASIHTTPRequestConfig.h"
|
||||
|
||||
typedef enum _ASIPostFormat {
|
||||
ASIMultipartFormDataPostFormat = 0,
|
||||
ASIURLEncodedPostFormat = 1
|
||||
|
||||
} ASIPostFormat;
|
||||
|
||||
@interface ASIFormDataRequest : ASIHTTPRequest <NSCopying> {
|
||||
|
||||
// Parameters that will be POSTed to the url
|
||||
NSMutableArray *postData;
|
||||
|
||||
// Files that will be POSTed to the url
|
||||
NSMutableArray *fileData;
|
||||
|
||||
ASIPostFormat postFormat;
|
||||
|
||||
NSStringEncoding stringEncoding;
|
||||
|
||||
#if DEBUG_FORM_DATA_REQUEST
|
||||
// Will store a string version of the request body that will be printed to the console when ASIHTTPREQUEST_DEBUG is set in GCC_PREPROCESSOR_DEFINITIONS
|
||||
NSString *debugBodyString;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#pragma mark utilities
|
||||
- (NSString*)encodeURL:(NSString *)string;
|
||||
|
||||
#pragma mark setup request
|
||||
|
||||
// Add a POST variable to the request
|
||||
- (void)addPostValue:(id <NSObject>)value forKey:(NSString *)key;
|
||||
|
||||
// Set a POST variable for this request, clearing any others with the same key
|
||||
- (void)setPostValue:(id <NSObject>)value forKey:(NSString *)key;
|
||||
|
||||
// Add the contents of a local file to the request
|
||||
- (void)addFile:(NSString *)filePath forKey:(NSString *)key;
|
||||
|
||||
// Same as above, but you can specify the content-type and file name
|
||||
- (void)addFile:(NSString *)filePath withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key;
|
||||
|
||||
// Add the contents of a local file to the request, clearing any others with the same key
|
||||
- (void)setFile:(NSString *)filePath forKey:(NSString *)key;
|
||||
|
||||
// Same as above, but you can specify the content-type and file name
|
||||
- (void)setFile:(NSString *)filePath withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key;
|
||||
|
||||
// Add the contents of an NSData object to the request
|
||||
- (void)addData:(NSData *)data forKey:(NSString *)key;
|
||||
|
||||
// Same as above, but you can specify the content-type and file name
|
||||
- (void)addData:(id)data withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key;
|
||||
|
||||
// Add the contents of an NSData object to the request, clearing any others with the same key
|
||||
- (void)setData:(NSData *)data forKey:(NSString *)key;
|
||||
|
||||
// Same as above, but you can specify the content-type and file name
|
||||
- (void)setData:(id)data withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key;
|
||||
|
||||
|
||||
@property (assign) ASIPostFormat postFormat;
|
||||
@property (assign) NSStringEncoding stringEncoding;
|
||||
@end
|
||||
362
msext/Class/Common/ASIHttpRequest/ASIFormDataRequest.m
Executable file
362
msext/Class/Common/ASIHttpRequest/ASIFormDataRequest.m
Executable file
@@ -0,0 +1,362 @@
|
||||
//
|
||||
// ASIFormDataRequest.m
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 07/11/2008.
|
||||
// Copyright 2008-2009 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ASIFormDataRequest.h"
|
||||
|
||||
|
||||
// Private stuff
|
||||
@interface ASIFormDataRequest ()
|
||||
- (void)buildMultipartFormDataPostBody;
|
||||
- (void)buildURLEncodedPostBody;
|
||||
- (void)appendPostString:(NSString *)string;
|
||||
|
||||
@property (retain) NSMutableArray *postData;
|
||||
@property (retain) NSMutableArray *fileData;
|
||||
|
||||
#if DEBUG_FORM_DATA_REQUEST
|
||||
- (void)addToDebugBody:(NSString *)string;
|
||||
@property (retain, nonatomic) NSString *debugBodyString;
|
||||
#endif
|
||||
|
||||
@end
|
||||
|
||||
@implementation ASIFormDataRequest
|
||||
|
||||
#pragma mark utilities
|
||||
- (NSString*)encodeURL:(NSString *)string
|
||||
{
|
||||
NSString *newString = [NSMakeCollectable(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)string, NULL, CFSTR(":/?#[]@!$ &'()*+,;=\"<>%{}|\\^~`"), CFStringConvertNSStringEncodingToEncoding([self stringEncoding]))) autorelease];
|
||||
if (newString) {
|
||||
return newString;
|
||||
}
|
||||
return @"";
|
||||
}
|
||||
|
||||
#pragma mark init / dealloc
|
||||
|
||||
+ (id)requestWithURL:(NSURL *)newURL
|
||||
{
|
||||
return [[[self alloc] initWithURL:newURL] autorelease];
|
||||
}
|
||||
|
||||
- (id)initWithURL:(NSURL *)newURL
|
||||
{
|
||||
self = [super initWithURL:newURL];
|
||||
[self setPostFormat:ASIURLEncodedPostFormat];
|
||||
[self setStringEncoding:NSUTF8StringEncoding];
|
||||
[self setRequestMethod:@"POST"];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
#if DEBUG_FORM_DATA_REQUEST
|
||||
[debugBodyString release];
|
||||
#endif
|
||||
|
||||
[postData release];
|
||||
[fileData release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
#pragma mark setup request
|
||||
|
||||
- (void)addPostValue:(id <NSObject>)value forKey:(NSString *)key
|
||||
{
|
||||
if (!key) {
|
||||
return;
|
||||
}
|
||||
if (![self postData]) {
|
||||
[self setPostData:[NSMutableArray array]];
|
||||
}
|
||||
NSMutableDictionary *keyValuePair = [NSMutableDictionary dictionaryWithCapacity:2];
|
||||
[keyValuePair setValue:key forKey:@"key"];
|
||||
[keyValuePair setValue:[value description] forKey:@"value"];
|
||||
[[self postData] addObject:keyValuePair];
|
||||
}
|
||||
|
||||
- (void)setPostValue:(id <NSObject>)value forKey:(NSString *)key
|
||||
{
|
||||
// Remove any existing value
|
||||
NSUInteger i;
|
||||
for (i=0; i<[[self postData] count]; i++) {
|
||||
NSDictionary *val = [[self postData] objectAtIndex:i];
|
||||
if ([[val objectForKey:@"key"] isEqualToString:key]) {
|
||||
[[self postData] removeObjectAtIndex:i];
|
||||
i--;
|
||||
}
|
||||
}
|
||||
[self addPostValue:value forKey:key];
|
||||
}
|
||||
|
||||
|
||||
- (void)addFile:(NSString *)filePath forKey:(NSString *)key
|
||||
{
|
||||
[self addFile:filePath withFileName:nil andContentType:nil forKey:key];
|
||||
}
|
||||
|
||||
- (void)addFile:(NSString *)filePath withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key
|
||||
{
|
||||
BOOL isDirectory = NO;
|
||||
BOOL fileExists = [[[[NSFileManager alloc] init] autorelease] fileExistsAtPath:filePath isDirectory:&isDirectory];
|
||||
if (!fileExists || isDirectory) {
|
||||
[self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIInternalErrorWhileBuildingRequestType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"No file exists at %@",filePath],NSLocalizedDescriptionKey,nil]]];
|
||||
}
|
||||
|
||||
// If the caller didn't specify a custom file name, we'll use the file name of the file we were passed
|
||||
if (!fileName) {
|
||||
fileName = [filePath lastPathComponent];
|
||||
}
|
||||
|
||||
// If we were given the path to a file, and the user didn't specify a mime type, we can detect it from the file extension
|
||||
if (!contentType) {
|
||||
contentType = [ASIHTTPRequest mimeTypeForFileAtPath:filePath];
|
||||
}
|
||||
[self addData:filePath withFileName:fileName andContentType:contentType forKey:key];
|
||||
}
|
||||
|
||||
- (void)setFile:(NSString *)filePath forKey:(NSString *)key
|
||||
{
|
||||
[self setFile:filePath withFileName:nil andContentType:nil forKey:key];
|
||||
}
|
||||
|
||||
- (void)setFile:(id)data withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key
|
||||
{
|
||||
// Remove any existing value
|
||||
NSUInteger i;
|
||||
for (i=0; i<[[self fileData] count]; i++) {
|
||||
NSDictionary *val = [[self fileData] objectAtIndex:i];
|
||||
if ([[val objectForKey:@"key"] isEqualToString:key]) {
|
||||
[[self fileData] removeObjectAtIndex:i];
|
||||
i--;
|
||||
}
|
||||
}
|
||||
[self addFile:data withFileName:fileName andContentType:contentType forKey:key];
|
||||
}
|
||||
|
||||
- (void)addData:(NSData *)data forKey:(NSString *)key
|
||||
{
|
||||
[self addData:data withFileName:@"file" andContentType:nil forKey:key];
|
||||
}
|
||||
|
||||
- (void)addData:(id)data withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key
|
||||
{
|
||||
if (![self fileData]) {
|
||||
[self setFileData:[NSMutableArray array]];
|
||||
}
|
||||
if (!contentType) {
|
||||
contentType = @"application/octet-stream";
|
||||
}
|
||||
|
||||
NSMutableDictionary *fileInfo = [NSMutableDictionary dictionaryWithCapacity:4];
|
||||
[fileInfo setValue:key forKey:@"key"];
|
||||
[fileInfo setValue:fileName forKey:@"fileName"];
|
||||
[fileInfo setValue:contentType forKey:@"contentType"];
|
||||
[fileInfo setValue:data forKey:@"data"];
|
||||
|
||||
[[self fileData] addObject:fileInfo];
|
||||
}
|
||||
|
||||
- (void)setData:(NSData *)data forKey:(NSString *)key
|
||||
{
|
||||
[self setData:data withFileName:@"file" andContentType:nil forKey:key];
|
||||
}
|
||||
|
||||
- (void)setData:(id)data withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key
|
||||
{
|
||||
// Remove any existing value
|
||||
NSUInteger i;
|
||||
for (i=0; i<[[self fileData] count]; i++) {
|
||||
NSDictionary *val = [[self fileData] objectAtIndex:i];
|
||||
if ([[val objectForKey:@"key"] isEqualToString:key]) {
|
||||
[[self fileData] removeObjectAtIndex:i];
|
||||
i--;
|
||||
}
|
||||
}
|
||||
[self addData:data withFileName:fileName andContentType:contentType forKey:key];
|
||||
}
|
||||
|
||||
- (void)buildPostBody
|
||||
{
|
||||
if ([self haveBuiltPostBody]) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if DEBUG_FORM_DATA_REQUEST
|
||||
[self setDebugBodyString:@""];
|
||||
#endif
|
||||
|
||||
if (![self postData] && ![self fileData]) {
|
||||
[super buildPostBody];
|
||||
return;
|
||||
}
|
||||
if ([[self fileData] count] > 0) {
|
||||
[self setShouldStreamPostDataFromDisk:YES];
|
||||
}
|
||||
|
||||
if ([self postFormat] == ASIURLEncodedPostFormat) {
|
||||
[self buildURLEncodedPostBody];
|
||||
} else {
|
||||
[self buildMultipartFormDataPostBody];
|
||||
}
|
||||
|
||||
[super buildPostBody];
|
||||
|
||||
#if DEBUG_FORM_DATA_REQUEST
|
||||
ASI_DEBUG_LOG(@"%@",[self debugBodyString]);
|
||||
[self setDebugBodyString:nil];
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
- (void)buildMultipartFormDataPostBody
|
||||
{
|
||||
#if DEBUG_FORM_DATA_REQUEST
|
||||
[self addToDebugBody:@"\r\n==== Building a multipart/form-data body ====\r\n"];
|
||||
#endif
|
||||
|
||||
NSString *charset = (NSString *)CFStringConvertEncodingToIANACharSetName(CFStringConvertNSStringEncodingToEncoding([self stringEncoding]));
|
||||
|
||||
// We don't bother to check if post data contains the boundary, since it's pretty unlikely that it does.
|
||||
CFUUIDRef uuid = CFUUIDCreate(nil);
|
||||
NSString *uuidString = [(NSString*)CFUUIDCreateString(nil, uuid) autorelease];
|
||||
CFRelease(uuid);
|
||||
NSString *stringBoundary = [NSString stringWithFormat:@"0xKhTmLbOuNdArY-%@",uuidString];
|
||||
|
||||
[self addRequestHeader:@"Content-Type" value:[NSString stringWithFormat:@"multipart/form-data; charset=%@; boundary=%@", charset, stringBoundary]];
|
||||
|
||||
[self appendPostString:[NSString stringWithFormat:@"--%@\r\n",stringBoundary]];
|
||||
|
||||
// Adds post data
|
||||
NSString *endItemBoundary = [NSString stringWithFormat:@"\r\n--%@\r\n",stringBoundary];
|
||||
NSUInteger i=0;
|
||||
for (NSDictionary *val in [self postData]) {
|
||||
[self appendPostString:[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n",[val objectForKey:@"key"]]];
|
||||
[self appendPostString:[val objectForKey:@"value"]];
|
||||
i++;
|
||||
if (i != [[self postData] count] || [[self fileData] count] > 0) { //Only add the boundary if this is not the last item in the post body
|
||||
[self appendPostString:endItemBoundary];
|
||||
}
|
||||
}
|
||||
|
||||
// Adds files to upload
|
||||
i=0;
|
||||
for (NSDictionary *val in [self fileData]) {
|
||||
|
||||
[self appendPostString:[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", [val objectForKey:@"key"], [val objectForKey:@"fileName"]]];
|
||||
[self appendPostString:[NSString stringWithFormat:@"Content-Type: %@\r\n\r\n", [val objectForKey:@"contentType"]]];
|
||||
|
||||
id data = [val objectForKey:@"data"];
|
||||
if ([data isKindOfClass:[NSString class]]) {
|
||||
[self appendPostDataFromFile:data];
|
||||
} else {
|
||||
[self appendPostData:data];
|
||||
}
|
||||
i++;
|
||||
// Only add the boundary if this is not the last item in the post body
|
||||
if (i != [[self fileData] count]) {
|
||||
[self appendPostString:endItemBoundary];
|
||||
}
|
||||
}
|
||||
|
||||
[self appendPostString:[NSString stringWithFormat:@"\r\n--%@--\r\n",stringBoundary]];
|
||||
|
||||
#if DEBUG_FORM_DATA_REQUEST
|
||||
[self addToDebugBody:@"==== End of multipart/form-data body ====\r\n"];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)buildURLEncodedPostBody
|
||||
{
|
||||
|
||||
// We can't post binary data using application/x-www-form-urlencoded
|
||||
if ([[self fileData] count] > 0) {
|
||||
[self setPostFormat:ASIMultipartFormDataPostFormat];
|
||||
[self buildMultipartFormDataPostBody];
|
||||
return;
|
||||
}
|
||||
|
||||
#if DEBUG_FORM_DATA_REQUEST
|
||||
[self addToDebugBody:@"\r\n==== Building an application/x-www-form-urlencoded body ====\r\n"];
|
||||
#endif
|
||||
|
||||
|
||||
NSString *charset = (NSString *)CFStringConvertEncodingToIANACharSetName(CFStringConvertNSStringEncodingToEncoding([self stringEncoding]));
|
||||
|
||||
[self addRequestHeader:@"Content-Type" value:[NSString stringWithFormat:@"application/x-www-form-urlencoded; charset=%@",charset]];
|
||||
|
||||
|
||||
NSUInteger i=0;
|
||||
NSUInteger count = [[self postData] count]-1;
|
||||
for (NSDictionary *val in [self postData]) {
|
||||
NSString *data = [NSString stringWithFormat:@"%@=%@%@", [self encodeURL:[val objectForKey:@"key"]], [self encodeURL:[val objectForKey:@"value"]],(i<count ? @"&" : @"")];
|
||||
[self appendPostString:data];
|
||||
i++;
|
||||
}
|
||||
#if DEBUG_FORM_DATA_REQUEST
|
||||
[self addToDebugBody:@"\r\n==== End of application/x-www-form-urlencoded body ====\r\n"];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)appendPostString:(NSString *)string
|
||||
{
|
||||
#if DEBUG_FORM_DATA_REQUEST
|
||||
[self addToDebugBody:string];
|
||||
#endif
|
||||
[super appendPostData:[string dataUsingEncoding:[self stringEncoding]]];
|
||||
}
|
||||
|
||||
#if DEBUG_FORM_DATA_REQUEST
|
||||
- (void)appendPostData:(NSData *)data
|
||||
{
|
||||
[self addToDebugBody:[NSString stringWithFormat:@"[%lu bytes of data]",(unsigned long)[data length]]];
|
||||
[super appendPostData:data];
|
||||
}
|
||||
|
||||
- (void)appendPostDataFromFile:(NSString *)file
|
||||
{
|
||||
NSError *err = nil;
|
||||
unsigned long long fileSize = [[[[[[NSFileManager alloc] init] autorelease] attributesOfItemAtPath:file error:&err] objectForKey:NSFileSize] unsignedLongLongValue];
|
||||
if (err) {
|
||||
[self addToDebugBody:[NSString stringWithFormat:@"[Error: Failed to obtain the size of the file at '%@']",file]];
|
||||
} else {
|
||||
[self addToDebugBody:[NSString stringWithFormat:@"[%llu bytes of data from file '%@']",fileSize,file]];
|
||||
}
|
||||
|
||||
[super appendPostDataFromFile:file];
|
||||
}
|
||||
|
||||
- (void)addToDebugBody:(NSString *)string
|
||||
{
|
||||
if (string) {
|
||||
[self setDebugBodyString:[[self debugBodyString] stringByAppendingString:string]];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#pragma mark NSCopying
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
ASIFormDataRequest *newRequest = [super copyWithZone:zone];
|
||||
[newRequest setPostData:[[[self postData] mutableCopyWithZone:zone] autorelease]];
|
||||
[newRequest setFileData:[[[self fileData] mutableCopyWithZone:zone] autorelease]];
|
||||
[newRequest setPostFormat:[self postFormat]];
|
||||
[newRequest setStringEncoding:[self stringEncoding]];
|
||||
[newRequest setRequestMethod:[self requestMethod]];
|
||||
return newRequest;
|
||||
}
|
||||
|
||||
@synthesize postData;
|
||||
@synthesize fileData;
|
||||
@synthesize postFormat;
|
||||
@synthesize stringEncoding;
|
||||
#if DEBUG_FORM_DATA_REQUEST
|
||||
@synthesize debugBodyString;
|
||||
#endif
|
||||
@end
|
||||
1004
msext/Class/Common/ASIHttpRequest/ASIHTTPRequest.h
Executable file
1004
msext/Class/Common/ASIHttpRequest/ASIHTTPRequest.h
Executable file
File diff suppressed because it is too large
Load Diff
5133
msext/Class/Common/ASIHttpRequest/ASIHTTPRequest.m
Executable file
5133
msext/Class/Common/ASIHttpRequest/ASIHTTPRequest.m
Executable file
File diff suppressed because it is too large
Load Diff
43
msext/Class/Common/ASIHttpRequest/ASIHTTPRequestConfig.h
Executable file
43
msext/Class/Common/ASIHttpRequest/ASIHTTPRequestConfig.h
Executable file
@@ -0,0 +1,43 @@
|
||||
//
|
||||
// ASIHTTPRequestConfig.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 14/12/2009.
|
||||
// Copyright 2009 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
// ======
|
||||
// Debug output configuration options
|
||||
// ======
|
||||
|
||||
// If defined will use the specified function for debug logging
|
||||
// Otherwise use NSLog
|
||||
#ifndef ASI_DEBUG_LOG
|
||||
#define ASI_DEBUG_LOG NSLog
|
||||
#endif
|
||||
|
||||
// When set to 1 ASIHTTPRequests will print information about what a request is doing
|
||||
#ifndef DEBUG_REQUEST_STATUS
|
||||
#define DEBUG_REQUEST_STATUS 0
|
||||
#endif
|
||||
|
||||
// When set to 1, ASIFormDataRequests will print information about the request body to the console
|
||||
#ifndef DEBUG_FORM_DATA_REQUEST
|
||||
#define DEBUG_FORM_DATA_REQUEST 0
|
||||
#endif
|
||||
|
||||
// When set to 1, ASIHTTPRequests will print information about bandwidth throttling to the console
|
||||
#ifndef DEBUG_THROTTLING
|
||||
#define DEBUG_THROTTLING 0
|
||||
#endif
|
||||
|
||||
// When set to 1, ASIHTTPRequests will print information about persistent connections to the console
|
||||
#ifndef DEBUG_PERSISTENT_CONNECTIONS
|
||||
#define DEBUG_PERSISTENT_CONNECTIONS 0
|
||||
#endif
|
||||
|
||||
// When set to 1, ASIHTTPRequests will print information about HTTP authentication (Basic, Digest or NTLM) to the console
|
||||
#ifndef DEBUG_HTTP_AUTHENTICATION
|
||||
#define DEBUG_HTTP_AUTHENTICATION 0
|
||||
#endif
|
||||
35
msext/Class/Common/ASIHttpRequest/ASIHTTPRequestDelegate.h
Executable file
35
msext/Class/Common/ASIHttpRequest/ASIHTTPRequestDelegate.h
Executable file
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// ASIHTTPRequestDelegate.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 13/04/2010.
|
||||
// Copyright 2010 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
@class ASIHTTPRequest;
|
||||
|
||||
@protocol ASIHTTPRequestDelegate <NSObject>
|
||||
|
||||
@optional
|
||||
|
||||
// These are the default delegate methods for request status
|
||||
// You can use different ones by setting didStartSelector / didFinishSelector / didFailSelector
|
||||
- (void)requestStarted:(ASIHTTPRequest *)request;
|
||||
- (void)request:(ASIHTTPRequest *)request didReceiveResponseHeaders:(NSDictionary *)responseHeaders;
|
||||
- (void)request:(ASIHTTPRequest *)request willRedirectToURL:(NSURL *)newURL;
|
||||
- (void)requestFinished:(ASIHTTPRequest *)request;
|
||||
- (void)requestFailed:(ASIHTTPRequest *)request;
|
||||
- (void)requestRedirected:(ASIHTTPRequest *)request;
|
||||
|
||||
// When a delegate implements this method, it is expected to process all incoming data itself
|
||||
// This means that responseData / responseString / downloadDestinationPath etc are ignored
|
||||
// You can have the request call a different method by setting didReceiveDataSelector
|
||||
- (void)request:(ASIHTTPRequest *)request didReceiveData:(NSData *)data;
|
||||
|
||||
// If a delegate implements one of these, it will be asked to supply credentials when none are available
|
||||
// The delegate can then either restart the request ([request retryUsingSuppliedCredentials]) once credentials have been set
|
||||
// or cancel it ([request cancelAuthentication])
|
||||
- (void)authenticationNeededForRequest:(ASIHTTPRequest *)request;
|
||||
- (void)proxyAuthenticationNeededForRequest:(ASIHTTPRequest *)request;
|
||||
|
||||
@end
|
||||
26
msext/Class/Common/ASIHttpRequest/ASIInputStream.h
Executable file
26
msext/Class/Common/ASIHttpRequest/ASIInputStream.h
Executable file
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// ASIInputStream.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 10/08/2009.
|
||||
// Copyright 2009 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class ASIHTTPRequest;
|
||||
|
||||
// This is a wrapper for NSInputStream that pretends to be an NSInputStream itself
|
||||
// Subclassing NSInputStream seems to be tricky, and may involve overriding undocumented methods, so we'll cheat instead.
|
||||
// It is used by ASIHTTPRequest whenever we have a request body, and handles measuring and throttling the bandwidth used for uploading
|
||||
|
||||
@interface ASIInputStream : NSObject {
|
||||
NSInputStream *stream;
|
||||
ASIHTTPRequest *request;
|
||||
}
|
||||
+ (id)inputStreamWithFileAtPath:(NSString *)path request:(ASIHTTPRequest *)request;
|
||||
+ (id)inputStreamWithData:(NSData *)data request:(ASIHTTPRequest *)request;
|
||||
|
||||
@property (retain, nonatomic) NSInputStream *stream;
|
||||
@property (assign, nonatomic) ASIHTTPRequest *request;
|
||||
@end
|
||||
138
msext/Class/Common/ASIHttpRequest/ASIInputStream.m
Executable file
138
msext/Class/Common/ASIHttpRequest/ASIInputStream.m
Executable file
@@ -0,0 +1,138 @@
|
||||
//
|
||||
// ASIInputStream.m
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 10/08/2009.
|
||||
// Copyright 2009 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ASIInputStream.h"
|
||||
#import "ASIHTTPRequest.h"
|
||||
|
||||
// Used to ensure only one request can read data at once
|
||||
static NSLock *readLock = nil;
|
||||
|
||||
@implementation ASIInputStream
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
if (self == [ASIInputStream class]) {
|
||||
readLock = [[NSLock alloc] init];
|
||||
}
|
||||
}
|
||||
|
||||
+ (id)inputStreamWithFileAtPath:(NSString *)path request:(ASIHTTPRequest *)theRequest
|
||||
{
|
||||
ASIInputStream *theStream = [[[self alloc] init] autorelease];
|
||||
[theStream setRequest:theRequest];
|
||||
[theStream setStream:[NSInputStream inputStreamWithFileAtPath:path]];
|
||||
return theStream;
|
||||
}
|
||||
|
||||
+ (id)inputStreamWithData:(NSData *)data request:(ASIHTTPRequest *)theRequest
|
||||
{
|
||||
ASIInputStream *theStream = [[[self alloc] init] autorelease];
|
||||
[theStream setRequest:theRequest];
|
||||
[theStream setStream:[NSInputStream inputStreamWithData:data]];
|
||||
return theStream;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[stream release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
// Called when CFNetwork wants to read more of our request body
|
||||
// When throttling is on, we ask ASIHTTPRequest for the maximum amount of data we can read
|
||||
- (NSInteger)read:(uint8_t *)buffer maxLength:(NSUInteger)len
|
||||
{
|
||||
[readLock lock];
|
||||
unsigned long toRead = len;
|
||||
if ([ASIHTTPRequest isBandwidthThrottled]) {
|
||||
toRead = [ASIHTTPRequest maxUploadReadLength];
|
||||
if (toRead > len) {
|
||||
toRead = len;
|
||||
} else if (toRead == 0) {
|
||||
toRead = 1;
|
||||
}
|
||||
[request performThrottling];
|
||||
}
|
||||
[readLock unlock];
|
||||
NSInteger rv = [stream read:buffer maxLength:toRead];
|
||||
if (rv > 0)
|
||||
[ASIHTTPRequest incrementBandwidthUsedInLastSecond:rv];
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
* Implement NSInputStream mandatory methods to make sure they are implemented
|
||||
* (necessary for MacRuby for example) and avoid the overhead of method
|
||||
* forwarding for these common methods.
|
||||
*/
|
||||
- (void)open
|
||||
{
|
||||
[stream open];
|
||||
}
|
||||
|
||||
- (void)close
|
||||
{
|
||||
[stream close];
|
||||
}
|
||||
|
||||
- (id)delegate
|
||||
{
|
||||
return [stream delegate];
|
||||
}
|
||||
|
||||
- (void)setDelegate:(id)delegate
|
||||
{
|
||||
[stream setDelegate:delegate];
|
||||
}
|
||||
|
||||
- (void)scheduleInRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode
|
||||
{
|
||||
[stream scheduleInRunLoop:aRunLoop forMode:mode];
|
||||
}
|
||||
|
||||
- (void)removeFromRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode
|
||||
{
|
||||
[stream removeFromRunLoop:aRunLoop forMode:mode];
|
||||
}
|
||||
|
||||
- (id)propertyForKey:(NSString *)key
|
||||
{
|
||||
return [stream propertyForKey:key];
|
||||
}
|
||||
|
||||
- (BOOL)setProperty:(id)property forKey:(NSString *)key
|
||||
{
|
||||
return [stream setProperty:property forKey:key];
|
||||
}
|
||||
|
||||
- (NSStreamStatus)streamStatus
|
||||
{
|
||||
return [stream streamStatus];
|
||||
}
|
||||
|
||||
- (NSError *)streamError
|
||||
{
|
||||
return [stream streamError];
|
||||
}
|
||||
|
||||
// If we get asked to perform a method we don't have (probably internal ones),
|
||||
// we'll just forward the message to our stream
|
||||
|
||||
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
|
||||
{
|
||||
return [stream methodSignatureForSelector:aSelector];
|
||||
}
|
||||
|
||||
- (void)forwardInvocation:(NSInvocation *)anInvocation
|
||||
{
|
||||
[anInvocation invokeWithTarget:stream];
|
||||
}
|
||||
|
||||
@synthesize stream;
|
||||
@synthesize request;
|
||||
@end
|
||||
16
msext/Class/Common/ASIHttpRequest/ASINSStringAdditions.h
Executable file
16
msext/Class/Common/ASIHttpRequest/ASINSStringAdditions.h
Executable file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// ASINSStringAdditions.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 12/09/2008.
|
||||
// Copyright 2008 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface NSString (CookieValueEncodingAdditions)
|
||||
|
||||
- (NSString *)encodedCookieValue;
|
||||
- (NSString *)decodedCookieValue;
|
||||
|
||||
@end
|
||||
28
msext/Class/Common/ASIHttpRequest/ASINSStringAdditions.m
Executable file
28
msext/Class/Common/ASIHttpRequest/ASINSStringAdditions.m
Executable file
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// ASINSStringAdditions.m
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 12/09/2008.
|
||||
// Copyright 2008 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ASINSStringAdditions.h"
|
||||
|
||||
@implementation NSString (CookieValueEncodingAdditions)
|
||||
|
||||
- (NSString *)decodedCookieValue
|
||||
{
|
||||
NSMutableString *s = [NSMutableString stringWithString:[self stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
|
||||
//Also swap plus signs for spaces
|
||||
[s replaceOccurrencesOfString:@"+" withString:@" " options:NSLiteralSearch range:NSMakeRange(0, [s length])];
|
||||
return [NSString stringWithString:s];
|
||||
}
|
||||
|
||||
- (NSString *)encodedCookieValue
|
||||
{
|
||||
return [self stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
108
msext/Class/Common/ASIHttpRequest/ASINetworkQueue.h
Executable file
108
msext/Class/Common/ASIHttpRequest/ASINetworkQueue.h
Executable file
@@ -0,0 +1,108 @@
|
||||
//
|
||||
// ASINetworkQueue.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 07/11/2008.
|
||||
// Copyright 2008-2009 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "ASIHTTPRequestDelegate.h"
|
||||
#import "ASIProgressDelegate.h"
|
||||
|
||||
@interface ASINetworkQueue : NSOperationQueue <ASIProgressDelegate, ASIHTTPRequestDelegate, NSCopying> {
|
||||
|
||||
// Delegate will get didFail + didFinish messages (if set)
|
||||
id delegate;
|
||||
|
||||
// Will be called when a request starts with the request as the argument
|
||||
SEL requestDidStartSelector;
|
||||
|
||||
// Will be called when a request receives response headers
|
||||
// Should take the form request:didRecieveResponseHeaders:, where the first argument is the request, and the second the headers dictionary
|
||||
SEL requestDidReceiveResponseHeadersSelector;
|
||||
|
||||
// Will be called when a request is about to redirect
|
||||
// Should take the form request:willRedirectToURL:, where the first argument is the request, and the second the new url
|
||||
SEL requestWillRedirectSelector;
|
||||
|
||||
// Will be called when a request completes with the request as the argument
|
||||
SEL requestDidFinishSelector;
|
||||
|
||||
// Will be called when a request fails with the request as the argument
|
||||
SEL requestDidFailSelector;
|
||||
|
||||
// Will be called when the queue finishes with the queue as the argument
|
||||
SEL queueDidFinishSelector;
|
||||
|
||||
// Upload progress indicator, probably an NSProgressIndicator or UIProgressView
|
||||
id uploadProgressDelegate;
|
||||
|
||||
// Total amount uploaded so far for all requests in this queue
|
||||
unsigned long long bytesUploadedSoFar;
|
||||
|
||||
// Total amount to be uploaded for all requests in this queue - requests add to this figure as they work out how much data they have to transmit
|
||||
unsigned long long totalBytesToUpload;
|
||||
|
||||
// Download progress indicator, probably an NSProgressIndicator or UIProgressView
|
||||
id downloadProgressDelegate;
|
||||
|
||||
// Total amount downloaded so far for all requests in this queue
|
||||
unsigned long long bytesDownloadedSoFar;
|
||||
|
||||
// Total amount to be downloaded for all requests in this queue - requests add to this figure as they receive Content-Length headers
|
||||
unsigned long long totalBytesToDownload;
|
||||
|
||||
// When YES, the queue will cancel all requests when a request fails. Default is YES
|
||||
BOOL shouldCancelAllRequestsOnFailure;
|
||||
|
||||
//Number of real requests (excludes HEAD requests created to manage showAccurateProgress)
|
||||
int requestsCount;
|
||||
|
||||
// When NO, this request will only update the progress indicator when it completes
|
||||
// When YES, this request will update the progress indicator according to how much data it has received so far
|
||||
// When YES, the queue will first perform HEAD requests for all GET requests in the queue, so it can calculate the total download size before it starts
|
||||
// NO means better performance, because it skips this step for GET requests, and it won't waste time updating the progress indicator until a request completes
|
||||
// Set to YES if the size of a requests in the queue varies greatly for much more accurate results
|
||||
// Default for requests in the queue is NO
|
||||
BOOL showAccurateProgress;
|
||||
|
||||
// Storage container for additional queue information.
|
||||
NSDictionary *userInfo;
|
||||
|
||||
}
|
||||
|
||||
// Convenience constructor
|
||||
+ (id)queue;
|
||||
|
||||
// Call this to reset a queue - it will cancel all operations, clear delegates, and suspend operation
|
||||
- (void)reset;
|
||||
|
||||
// Used internally to manage HEAD requests when showAccurateProgress is YES, do not use!
|
||||
- (void)addHEADOperation:(NSOperation *)operation;
|
||||
|
||||
// All ASINetworkQueues are paused when created so that total size can be calculated before the queue starts
|
||||
// This method will start the queue
|
||||
- (void)go;
|
||||
|
||||
@property (assign, nonatomic, setter=setUploadProgressDelegate:) id uploadProgressDelegate;
|
||||
@property (assign, nonatomic, setter=setDownloadProgressDelegate:) id downloadProgressDelegate;
|
||||
|
||||
@property (assign) SEL requestDidStartSelector;
|
||||
@property (assign) SEL requestDidReceiveResponseHeadersSelector;
|
||||
@property (assign) SEL requestWillRedirectSelector;
|
||||
@property (assign) SEL requestDidFinishSelector;
|
||||
@property (assign) SEL requestDidFailSelector;
|
||||
@property (assign) SEL queueDidFinishSelector;
|
||||
@property (assign) BOOL shouldCancelAllRequestsOnFailure;
|
||||
@property (assign) id delegate;
|
||||
@property (assign) BOOL showAccurateProgress;
|
||||
@property (assign, readonly) int requestsCount;
|
||||
@property (retain) NSDictionary *userInfo;
|
||||
|
||||
@property (assign) unsigned long long bytesUploadedSoFar;
|
||||
@property (assign) unsigned long long totalBytesToUpload;
|
||||
@property (assign) unsigned long long bytesDownloadedSoFar;
|
||||
@property (assign) unsigned long long totalBytesToDownload;
|
||||
|
||||
@end
|
||||
343
msext/Class/Common/ASIHttpRequest/ASINetworkQueue.m
Executable file
343
msext/Class/Common/ASIHttpRequest/ASINetworkQueue.m
Executable file
@@ -0,0 +1,343 @@
|
||||
//
|
||||
// ASINetworkQueue.m
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 07/11/2008.
|
||||
// Copyright 2008-2009 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ASINetworkQueue.h"
|
||||
#import "ASIHTTPRequest.h"
|
||||
|
||||
// Private stuff
|
||||
@interface ASINetworkQueue ()
|
||||
- (void)resetProgressDelegate:(id *)progressDelegate;
|
||||
@property (assign) int requestsCount;
|
||||
@end
|
||||
|
||||
@implementation ASINetworkQueue
|
||||
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
[self setShouldCancelAllRequestsOnFailure:YES];
|
||||
[self setMaxConcurrentOperationCount:4];
|
||||
[self setSuspended:YES];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (id)queue
|
||||
{
|
||||
return [[[self alloc] init] autorelease];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
//We need to clear the queue on any requests that haven't got around to cleaning up yet, as otherwise they'll try to let us know if something goes wrong, and we'll be long gone by then
|
||||
for (ASIHTTPRequest *request in [self operations]) {
|
||||
[request setQueue:nil];
|
||||
}
|
||||
[userInfo release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void)setSuspended:(BOOL)suspend
|
||||
{
|
||||
[super setSuspended:suspend];
|
||||
}
|
||||
|
||||
- (void)reset
|
||||
{
|
||||
[self cancelAllOperations];
|
||||
[self setDelegate:nil];
|
||||
[self setDownloadProgressDelegate:nil];
|
||||
[self setUploadProgressDelegate:nil];
|
||||
[self setRequestDidStartSelector:NULL];
|
||||
[self setRequestDidReceiveResponseHeadersSelector:NULL];
|
||||
[self setRequestDidFailSelector:NULL];
|
||||
[self setRequestDidFinishSelector:NULL];
|
||||
[self setQueueDidFinishSelector:NULL];
|
||||
[self setSuspended:YES];
|
||||
}
|
||||
|
||||
|
||||
- (void)go
|
||||
{
|
||||
[self setSuspended:NO];
|
||||
}
|
||||
|
||||
- (void)cancelAllOperations
|
||||
{
|
||||
[self setBytesUploadedSoFar:0];
|
||||
[self setTotalBytesToUpload:0];
|
||||
[self setBytesDownloadedSoFar:0];
|
||||
[self setTotalBytesToDownload:0];
|
||||
[super cancelAllOperations];
|
||||
}
|
||||
|
||||
- (void)setUploadProgressDelegate:(id)newDelegate
|
||||
{
|
||||
uploadProgressDelegate = newDelegate;
|
||||
[self resetProgressDelegate:&uploadProgressDelegate];
|
||||
|
||||
}
|
||||
|
||||
- (void)setDownloadProgressDelegate:(id)newDelegate
|
||||
{
|
||||
downloadProgressDelegate = newDelegate;
|
||||
[self resetProgressDelegate:&downloadProgressDelegate];
|
||||
}
|
||||
|
||||
- (void)resetProgressDelegate:(id *)progressDelegate
|
||||
{
|
||||
#if !TARGET_OS_IPHONE
|
||||
// If the uploadProgressDelegate is an NSProgressIndicator, we set its MaxValue to 1.0 so we can treat it similarly to UIProgressViews
|
||||
SEL selector = @selector(setMaxValue:);
|
||||
if ([*progressDelegate respondsToSelector:selector]) {
|
||||
double max = 1.0;
|
||||
[ASIHTTPRequest performSelector:selector onTarget:progressDelegate withObject:nil amount:&max callerToRetain:nil];
|
||||
}
|
||||
selector = @selector(setDoubleValue:);
|
||||
if ([*progressDelegate respondsToSelector:selector]) {
|
||||
double value = 0.0;
|
||||
[ASIHTTPRequest performSelector:selector onTarget:progressDelegate withObject:nil amount:&value callerToRetain:nil];
|
||||
}
|
||||
#else
|
||||
SEL selector = @selector(setProgress:);
|
||||
if ([*progressDelegate respondsToSelector:selector]) {
|
||||
float value = 0.0f;
|
||||
[ASIHTTPRequest performSelector:selector onTarget:progressDelegate withObject:nil amount:&value callerToRetain:nil];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)addHEADOperation:(NSOperation *)operation
|
||||
{
|
||||
if ([operation isKindOfClass:[ASIHTTPRequest class]]) {
|
||||
|
||||
ASIHTTPRequest *request = (ASIHTTPRequest *)operation;
|
||||
[request setRequestMethod:@"HEAD"];
|
||||
[request setQueuePriority:10];
|
||||
[request setShowAccurateProgress:YES];
|
||||
[request setQueue:self];
|
||||
|
||||
// Important - we are calling NSOperation's add method - we don't want to add this as a normal request!
|
||||
[super addOperation:request];
|
||||
}
|
||||
}
|
||||
|
||||
// Only add ASIHTTPRequests to this queue!!
|
||||
- (void)addOperation:(NSOperation *)operation
|
||||
{
|
||||
if (![operation isKindOfClass:[ASIHTTPRequest class]]) {
|
||||
[NSException raise:@"AttemptToAddInvalidRequest" format:@"Attempted to add an object that was not an ASIHTTPRequest to an ASINetworkQueue"];
|
||||
}
|
||||
|
||||
[self setRequestsCount:[self requestsCount]+1];
|
||||
|
||||
ASIHTTPRequest *request = (ASIHTTPRequest *)operation;
|
||||
|
||||
if ([self showAccurateProgress]) {
|
||||
|
||||
// Force the request to build its body (this may change requestMethod)
|
||||
[request buildPostBody];
|
||||
|
||||
// If this is a GET request and we want accurate progress, perform a HEAD request first to get the content-length
|
||||
// We'll only do this before the queue is started
|
||||
// If requests are added after the queue is started they will probably move the overall progress backwards anyway, so there's no value performing the HEAD requests first
|
||||
// Instead, they'll update the total progress if and when they receive a content-length header
|
||||
if ([[request requestMethod] isEqualToString:@"GET"]) {
|
||||
if ([self isSuspended]) {
|
||||
ASIHTTPRequest *HEADRequest = [request HEADRequest];
|
||||
[self addHEADOperation:HEADRequest];
|
||||
[request addDependency:HEADRequest];
|
||||
if ([request shouldResetDownloadProgress]) {
|
||||
[self resetProgressDelegate:&downloadProgressDelegate];
|
||||
[request setShouldResetDownloadProgress:NO];
|
||||
}
|
||||
}
|
||||
}
|
||||
[request buildPostBody];
|
||||
[self request:nil incrementUploadSizeBy:[request postLength]];
|
||||
|
||||
|
||||
} else {
|
||||
[self request:nil incrementDownloadSizeBy:1];
|
||||
[self request:nil incrementUploadSizeBy:1];
|
||||
}
|
||||
// Tell the request not to increment the upload size when it starts, as we've already added its length
|
||||
if ([request shouldResetUploadProgress]) {
|
||||
[self resetProgressDelegate:&uploadProgressDelegate];
|
||||
[request setShouldResetUploadProgress:NO];
|
||||
}
|
||||
|
||||
[request setShowAccurateProgress:[self showAccurateProgress]];
|
||||
|
||||
[request setQueue:self];
|
||||
[super addOperation:request];
|
||||
|
||||
}
|
||||
|
||||
- (void)requestStarted:(ASIHTTPRequest *)request
|
||||
{
|
||||
if ([self requestDidStartSelector]) {
|
||||
[[self delegate] performSelector:[self requestDidStartSelector] withObject:request];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)request:(ASIHTTPRequest *)request didReceiveResponseHeaders:(NSDictionary *)responseHeaders
|
||||
{
|
||||
if ([self requestDidReceiveResponseHeadersSelector]) {
|
||||
[[self delegate] performSelector:[self requestDidReceiveResponseHeadersSelector] withObject:request withObject:responseHeaders];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)request:(ASIHTTPRequest *)request willRedirectToURL:(NSURL *)newURL
|
||||
{
|
||||
if ([self requestWillRedirectSelector]) {
|
||||
[[self delegate] performSelector:[self requestWillRedirectSelector] withObject:request withObject:newURL];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)requestFinished:(ASIHTTPRequest *)request
|
||||
{
|
||||
[self setRequestsCount:[self requestsCount]-1];
|
||||
if ([self requestDidFinishSelector]) {
|
||||
[[self delegate] performSelector:[self requestDidFinishSelector] withObject:request];
|
||||
}
|
||||
if ([self requestsCount] == 0) {
|
||||
if ([self queueDidFinishSelector]) {
|
||||
[[self delegate] performSelector:[self queueDidFinishSelector] withObject:self];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)requestFailed:(ASIHTTPRequest *)request
|
||||
{
|
||||
[self setRequestsCount:[self requestsCount]-1];
|
||||
if ([self requestDidFailSelector]) {
|
||||
[[self delegate] performSelector:[self requestDidFailSelector] withObject:request];
|
||||
}
|
||||
if ([self requestsCount] == 0) {
|
||||
if ([self queueDidFinishSelector]) {
|
||||
[[self delegate] performSelector:[self queueDidFinishSelector] withObject:self];
|
||||
}
|
||||
}
|
||||
if ([self shouldCancelAllRequestsOnFailure] && [self requestsCount] > 0) {
|
||||
[self cancelAllOperations];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
- (void)request:(ASIHTTPRequest *)request didReceiveBytes:(long long)bytes
|
||||
{
|
||||
[self setBytesDownloadedSoFar:[self bytesDownloadedSoFar]+bytes];
|
||||
if ([self downloadProgressDelegate]) {
|
||||
[ASIHTTPRequest updateProgressIndicator:&downloadProgressDelegate withProgress:[self bytesDownloadedSoFar] ofTotal:[self totalBytesToDownload]];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)request:(ASIHTTPRequest *)request didSendBytes:(long long)bytes
|
||||
{
|
||||
[self setBytesUploadedSoFar:[self bytesUploadedSoFar]+bytes];
|
||||
if ([self uploadProgressDelegate]) {
|
||||
[ASIHTTPRequest updateProgressIndicator:&uploadProgressDelegate withProgress:[self bytesUploadedSoFar] ofTotal:[self totalBytesToUpload]];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)request:(ASIHTTPRequest *)request incrementDownloadSizeBy:(long long)newLength
|
||||
{
|
||||
[self setTotalBytesToDownload:[self totalBytesToDownload]+newLength];
|
||||
}
|
||||
|
||||
- (void)request:(ASIHTTPRequest *)request incrementUploadSizeBy:(long long)newLength
|
||||
{
|
||||
[self setTotalBytesToUpload:[self totalBytesToUpload]+newLength];
|
||||
}
|
||||
|
||||
|
||||
// Since this queue takes over as the delegate for all requests it contains, it should forward authorisation requests to its own delegate
|
||||
- (void)authenticationNeededForRequest:(ASIHTTPRequest *)request
|
||||
{
|
||||
if ([[self delegate] respondsToSelector:@selector(authenticationNeededForRequest:)]) {
|
||||
[[self delegate] performSelector:@selector(authenticationNeededForRequest:) withObject:request];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)proxyAuthenticationNeededForRequest:(ASIHTTPRequest *)request
|
||||
{
|
||||
if ([[self delegate] respondsToSelector:@selector(proxyAuthenticationNeededForRequest:)]) {
|
||||
[[self delegate] performSelector:@selector(proxyAuthenticationNeededForRequest:) withObject:request];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (BOOL)respondsToSelector:(SEL)selector
|
||||
{
|
||||
// We handle certain methods differently because whether our delegate implements them or not can affect how the request should behave
|
||||
|
||||
// If the delegate implements this, the request will stop to wait for credentials
|
||||
if (selector == @selector(authenticationNeededForRequest:)) {
|
||||
if ([[self delegate] respondsToSelector:@selector(authenticationNeededForRequest:)]) {
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
|
||||
// If the delegate implements this, the request will to wait for credentials
|
||||
} else if (selector == @selector(proxyAuthenticationNeededForRequest:)) {
|
||||
if ([[self delegate] respondsToSelector:@selector(proxyAuthenticationNeededForRequest:)]) {
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
|
||||
// If the delegate implements requestWillRedirectSelector, the request will stop to allow the delegate to change the url
|
||||
} else if (selector == @selector(request:willRedirectToURL:)) {
|
||||
if ([self requestWillRedirectSelector] && [[self delegate] respondsToSelector:[self requestWillRedirectSelector]]) {
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
return [super respondsToSelector:selector];
|
||||
}
|
||||
|
||||
#pragma mark NSCopying
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
ASINetworkQueue *newQueue = [[[self class] alloc] init];
|
||||
[newQueue setDelegate:[self delegate]];
|
||||
[newQueue setRequestDidStartSelector:[self requestDidStartSelector]];
|
||||
[newQueue setRequestWillRedirectSelector:[self requestWillRedirectSelector]];
|
||||
[newQueue setRequestDidReceiveResponseHeadersSelector:[self requestDidReceiveResponseHeadersSelector]];
|
||||
[newQueue setRequestDidFinishSelector:[self requestDidFinishSelector]];
|
||||
[newQueue setRequestDidFailSelector:[self requestDidFailSelector]];
|
||||
[newQueue setQueueDidFinishSelector:[self queueDidFinishSelector]];
|
||||
[newQueue setUploadProgressDelegate:[self uploadProgressDelegate]];
|
||||
[newQueue setDownloadProgressDelegate:[self downloadProgressDelegate]];
|
||||
[newQueue setShouldCancelAllRequestsOnFailure:[self shouldCancelAllRequestsOnFailure]];
|
||||
[newQueue setShowAccurateProgress:[self showAccurateProgress]];
|
||||
[newQueue setUserInfo:[[[self userInfo] copyWithZone:zone] autorelease]];
|
||||
return newQueue;
|
||||
}
|
||||
|
||||
|
||||
@synthesize requestsCount;
|
||||
@synthesize bytesUploadedSoFar;
|
||||
@synthesize totalBytesToUpload;
|
||||
@synthesize bytesDownloadedSoFar;
|
||||
@synthesize totalBytesToDownload;
|
||||
@synthesize shouldCancelAllRequestsOnFailure;
|
||||
@synthesize uploadProgressDelegate;
|
||||
@synthesize downloadProgressDelegate;
|
||||
@synthesize requestDidStartSelector;
|
||||
@synthesize requestDidReceiveResponseHeadersSelector;
|
||||
@synthesize requestWillRedirectSelector;
|
||||
@synthesize requestDidFinishSelector;
|
||||
@synthesize requestDidFailSelector;
|
||||
@synthesize queueDidFinishSelector;
|
||||
@synthesize delegate;
|
||||
@synthesize showAccurateProgress;
|
||||
@synthesize userInfo;
|
||||
@end
|
||||
38
msext/Class/Common/ASIHttpRequest/ASIProgressDelegate.h
Executable file
38
msext/Class/Common/ASIHttpRequest/ASIProgressDelegate.h
Executable file
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// ASIProgressDelegate.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 13/04/2010.
|
||||
// Copyright 2010 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
@class ASIHTTPRequest;
|
||||
|
||||
@protocol ASIProgressDelegate <NSObject>
|
||||
|
||||
@optional
|
||||
|
||||
// These methods are used to update UIProgressViews (iPhone OS) or NSProgressIndicators (Mac OS X)
|
||||
// If you are using a custom progress delegate, you may find it easier to implement didReceiveBytes / didSendBytes instead
|
||||
#if TARGET_OS_IPHONE
|
||||
- (void)setProgress:(float)newProgress;
|
||||
#else
|
||||
- (void)setDoubleValue:(double)newProgress;
|
||||
- (void)setMaxValue:(double)newMax;
|
||||
#endif
|
||||
|
||||
// Called when the request receives some data - bytes is the length of that data
|
||||
- (void)request:(ASIHTTPRequest *)request didReceiveBytes:(long long)bytes;
|
||||
|
||||
// Called when the request sends some data
|
||||
// The first 32KB (128KB on older platforms) of data sent is not included in this amount because of limitations with the CFNetwork API
|
||||
// bytes may be less than zero if a request needs to remove upload progress (probably because the request needs to run again)
|
||||
- (void)request:(ASIHTTPRequest *)request didSendBytes:(long long)bytes;
|
||||
|
||||
// Called when a request needs to change the length of the content to download
|
||||
- (void)request:(ASIHTTPRequest *)request incrementDownloadSizeBy:(long long)newLength;
|
||||
|
||||
// Called when a request needs to change the length of the content to upload
|
||||
// newLength may be less than zero when a request needs to remove the size of the internal buffer from progress tracking
|
||||
- (void)request:(ASIHTTPRequest *)request incrementUploadSizeBy:(long long)newLength;
|
||||
@end
|
||||
15
msext/Class/Common/ASIHttpRequest/NSHTTPCookieAdditions.h
Executable file
15
msext/Class/Common/ASIHttpRequest/NSHTTPCookieAdditions.h
Executable file
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// NSHTTPCookieAdditions.h
|
||||
// asi-http-request
|
||||
//
|
||||
// Created by Ben Copsey on 12/09/2008.
|
||||
// Copyright 2008 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
@interface NSHTTPCookie (ValueEncodingAdditions)
|
||||
|
||||
- (NSString *)encodedValue;
|
||||
- (NSString *)decodedValue;
|
||||
|
||||
@end
|
||||
28
msext/Class/Common/ASIHttpRequest/NSHTTPCookieAdditions.m
Executable file
28
msext/Class/Common/ASIHttpRequest/NSHTTPCookieAdditions.m
Executable file
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// NSHTTPCookieAdditions.m
|
||||
// asi-http-request
|
||||
//
|
||||
// Created by Ben Copsey on 12/09/2008.
|
||||
// Copyright 2008 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSHTTPCookieAdditions.h"
|
||||
|
||||
@implementation NSHTTPCookie (ValueEncodingAdditions)
|
||||
|
||||
- (NSString *)decodedValue
|
||||
{
|
||||
NSMutableString *s = [NSMutableString stringWithString:[[self value] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
|
||||
//Also swap plus signs for spaces
|
||||
[s replaceOccurrencesOfString:@"+" withString:@" " options:NSLiteralSearch range:NSMakeRange(0, [s length])];
|
||||
return [NSString stringWithString:s];
|
||||
}
|
||||
|
||||
- (NSString *)encodedValue
|
||||
{
|
||||
return [[self value] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
194
msext/Class/Common/ASIHttpRequest/Reachability.h
Executable file
194
msext/Class/Common/ASIHttpRequest/Reachability.h
Executable file
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
|
||||
File: Reachability.h
|
||||
Abstract: Basic demonstration of how to use the SystemConfiguration Reachablity APIs.
|
||||
|
||||
Version: 2.0.4ddg
|
||||
*/
|
||||
|
||||
/*
|
||||
Significant additions made by Andrew W. Donoho, August 11, 2009.
|
||||
This is a derived work of Apple's Reachability v2.0 class.
|
||||
|
||||
The below license is the new BSD license with the OSI recommended personalizations.
|
||||
<http://www.opensource.org/licenses/bsd-license.php>
|
||||
|
||||
Extensions Copyright (C) 2009 Donoho Design Group, LLC. All Rights Reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of Andrew W. Donoho nor Donoho Design Group, L.L.C.
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY DONOHO DESIGN GROUP, L.L.C. "AS IS" AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
|
||||
Apple's Original License on Reachability v2.0
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc.
|
||||
("Apple") in consideration of your agreement to the following terms, and your
|
||||
use, installation, modification or redistribution of this Apple software
|
||||
constitutes acceptance of these terms. If you do not agree with these terms,
|
||||
please do not use, install, modify or redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and subject
|
||||
to these terms, Apple grants you a personal, non-exclusive license, under
|
||||
Apple's copyrights in this original Apple software (the "Apple Software"), to
|
||||
use, reproduce, modify and redistribute the Apple Software, with or without
|
||||
modifications, in source and/or binary forms; provided that if you redistribute
|
||||
the Apple Software in its entirety and without modifications, you must retain
|
||||
this notice and the following text and disclaimers in all such redistributions
|
||||
of the Apple Software.
|
||||
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may be used
|
||||
to endorse or promote products derived from the Apple Software without specific
|
||||
prior written permission from Apple. Except as expressly stated in this notice,
|
||||
no other rights or licenses, express or implied, are granted by Apple herein,
|
||||
including but not limited to any patent rights that may be infringed by your
|
||||
derivative works or by other works in which the Apple Software may be
|
||||
incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
|
||||
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
|
||||
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
|
||||
COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR
|
||||
DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF
|
||||
CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
|
||||
APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2009 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
DDG extensions include:
|
||||
Each reachability object now has a copy of the key used to store it in a
|
||||
dictionary. This allows each observer to quickly determine if the event is
|
||||
important to them.
|
||||
|
||||
-currentReachabilityStatus also has a significantly different decision criteria than
|
||||
Apple's code.
|
||||
|
||||
A multiple convenience test methods have been added.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <SystemConfiguration/SystemConfiguration.h>
|
||||
#import <netinet/in.h>
|
||||
|
||||
#define USE_DDG_EXTENSIONS 1 // Use DDG's Extensions to test network criteria.
|
||||
// Since NSAssert and NSCAssert are used in this code,
|
||||
// I recommend you set NS_BLOCK_ASSERTIONS=1 in the release versions of your projects.
|
||||
|
||||
enum {
|
||||
|
||||
// DDG NetworkStatus Constant Names.
|
||||
kNotReachable = 0, // Apple's code depends upon 'NotReachable' being the same value as 'NO'.
|
||||
kReachableViaWWAN, // Switched order from Apple's enum. WWAN is active before WiFi.
|
||||
kReachableViaWiFi
|
||||
|
||||
};
|
||||
typedef uint32_t NetworkStatus;
|
||||
|
||||
enum {
|
||||
|
||||
// Apple NetworkStatus Constant Names.
|
||||
NotReachable = kNotReachable,
|
||||
ReachableViaWiFi = kReachableViaWiFi,
|
||||
ReachableViaWWAN = kReachableViaWWAN
|
||||
|
||||
};
|
||||
|
||||
|
||||
extern NSString *const kInternetConnection;
|
||||
extern NSString *const kLocalWiFiConnection;
|
||||
extern NSString *const kReachabilityChangedNotification;
|
||||
|
||||
@interface Reachability: NSObject {
|
||||
|
||||
@private
|
||||
NSString *key_;
|
||||
SCNetworkReachabilityRef reachabilityRef;
|
||||
|
||||
}
|
||||
|
||||
@property (copy) NSString *key; // Atomic because network operations are asynchronous.
|
||||
|
||||
// Designated Initializer.
|
||||
- (Reachability *) initWithReachabilityRef: (SCNetworkReachabilityRef) ref;
|
||||
|
||||
// Use to check the reachability of a particular host name.
|
||||
+ (Reachability *) reachabilityWithHostName: (NSString*) hostName;
|
||||
|
||||
// Use to check the reachability of a particular IP address.
|
||||
+ (Reachability *) reachabilityWithAddress: (const struct sockaddr_in*) hostAddress;
|
||||
|
||||
// Use to check whether the default route is available.
|
||||
// Should be used to, at minimum, establish network connectivity.
|
||||
+ (Reachability *) reachabilityForInternetConnection;
|
||||
|
||||
// Use to check whether a local wifi connection is available.
|
||||
+ (Reachability *) reachabilityForLocalWiFi;
|
||||
|
||||
//Start listening for reachability notifications on the current run loop.
|
||||
- (BOOL) startNotifier;
|
||||
- (void) stopNotifier;
|
||||
|
||||
// Comparison routines to enable choosing actions in a notification.
|
||||
- (BOOL) isEqual: (Reachability *) r;
|
||||
|
||||
// These are the status tests.
|
||||
- (NetworkStatus) currentReachabilityStatus;
|
||||
|
||||
// The main direct test of reachability.
|
||||
- (BOOL) isReachable;
|
||||
|
||||
// WWAN may be available, but not active until a connection has been established.
|
||||
// WiFi may require a connection for VPN on Demand.
|
||||
- (BOOL) isConnectionRequired; // Identical DDG variant.
|
||||
- (BOOL) connectionRequired; // Apple's routine.
|
||||
|
||||
// Dynamic, on demand connection?
|
||||
- (BOOL) isConnectionOnDemand;
|
||||
|
||||
// Is user intervention required?
|
||||
- (BOOL) isInterventionRequired;
|
||||
|
||||
// Routines for specific connection testing by your app.
|
||||
- (BOOL) isReachableViaWWAN;
|
||||
- (BOOL) isReachableViaWiFi;
|
||||
|
||||
- (SCNetworkReachabilityFlags) reachabilityFlags;
|
||||
|
||||
@end
|
||||
814
msext/Class/Common/ASIHttpRequest/Reachability.m
Executable file
814
msext/Class/Common/ASIHttpRequest/Reachability.m
Executable file
@@ -0,0 +1,814 @@
|
||||
/*
|
||||
|
||||
File: Reachability.m
|
||||
Abstract: Basic demonstration of how to use the SystemConfiguration Reachablity APIs.
|
||||
|
||||
Version: 2.0.4ddg
|
||||
*/
|
||||
|
||||
/*
|
||||
Significant additions made by Andrew W. Donoho, August 11, 2009.
|
||||
This is a derived work of Apple's Reachability v2.0 class.
|
||||
|
||||
The below license is the new BSD license with the OSI recommended personalizations.
|
||||
<http://www.opensource.org/licenses/bsd-license.php>
|
||||
|
||||
Extensions Copyright (C) 2009 Donoho Design Group, LLC. All Rights Reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of Andrew W. Donoho nor Donoho Design Group, L.L.C.
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY DONOHO DESIGN GROUP, L.L.C. "AS IS" AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
|
||||
Apple's Original License on Reachability v2.0
|
||||
|
||||
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc.
|
||||
("Apple") in consideration of your agreement to the following terms, and your
|
||||
use, installation, modification or redistribution of this Apple software
|
||||
constitutes acceptance of these terms. If you do not agree with these terms,
|
||||
please do not use, install, modify or redistribute this Apple software.
|
||||
|
||||
In consideration of your agreement to abide by the following terms, and subject
|
||||
to these terms, Apple grants you a personal, non-exclusive license, under
|
||||
Apple's copyrights in this original Apple software (the "Apple Software"), to
|
||||
use, reproduce, modify and redistribute the Apple Software, with or without
|
||||
modifications, in source and/or binary forms; provided that if you redistribute
|
||||
the Apple Software in its entirety and without modifications, you must retain
|
||||
this notice and the following text and disclaimers in all such redistributions
|
||||
of the Apple Software.
|
||||
|
||||
Neither the name, trademarks, service marks or logos of Apple Inc. may be used
|
||||
to endorse or promote products derived from the Apple Software without specific
|
||||
prior written permission from Apple. Except as expressly stated in this notice,
|
||||
no other rights or licenses, express or implied, are granted by Apple herein,
|
||||
including but not limited to any patent rights that may be infringed by your
|
||||
derivative works or by other works in which the Apple Software may be
|
||||
incorporated.
|
||||
|
||||
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
|
||||
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
|
||||
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
|
||||
COMBINATION WITH YOUR PRODUCTS.
|
||||
|
||||
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
|
||||
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR
|
||||
DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF
|
||||
CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
|
||||
APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Copyright (C) 2009 Apple Inc. All Rights Reserved.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
Each reachability object now has a copy of the key used to store it in a dictionary.
|
||||
This allows each observer to quickly determine if the event is important to them.
|
||||
*/
|
||||
|
||||
#import <sys/socket.h>
|
||||
#import <netinet/in.h>
|
||||
#import <netinet6/in6.h>
|
||||
#import <arpa/inet.h>
|
||||
#import <ifaddrs.h>
|
||||
#import <netdb.h>
|
||||
|
||||
#import <CoreFoundation/CoreFoundation.h>
|
||||
|
||||
#import "Reachability.h"
|
||||
|
||||
NSString *const kInternetConnection = @"InternetConnection";
|
||||
NSString *const kLocalWiFiConnection = @"LocalWiFiConnection";
|
||||
NSString *const kReachabilityChangedNotification = @"NetworkReachabilityChangedNotification";
|
||||
|
||||
#define CLASS_DEBUG 1 // Turn on logReachabilityFlags. Must also have a project wide defined DEBUG.
|
||||
|
||||
#if (defined DEBUG && defined CLASS_DEBUG)
|
||||
#define logReachabilityFlags(flags) (logReachabilityFlags_(__PRETTY_FUNCTION__, __LINE__, flags))
|
||||
|
||||
static NSString *reachabilityFlags_(SCNetworkReachabilityFlags flags) {
|
||||
|
||||
#if (__IPHONE_OS_VERSION_MIN_REQUIRED >= 30000) // Apple advises you to use the magic number instead of a symbol.
|
||||
return [NSString stringWithFormat:@"Reachability Flags: %c%c %c%c%c%c%c%c%c",
|
||||
(flags & kSCNetworkReachabilityFlagsIsWWAN) ? 'W' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsReachable) ? 'R' : '-',
|
||||
|
||||
(flags & kSCNetworkReachabilityFlagsConnectionRequired) ? 'c' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsTransientConnection) ? 't' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) ? 'C' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsConnectionOnDemand) ? 'D' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsIsLocalAddress) ? 'l' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsIsDirect) ? 'd' : '-'];
|
||||
#else
|
||||
// Compile out the v3.0 features for v2.2.1 deployment.
|
||||
return [NSString stringWithFormat:@"Reachability Flags: %c%c %c%c%c%c%c%c",
|
||||
(flags & kSCNetworkReachabilityFlagsIsWWAN) ? 'W' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsReachable) ? 'R' : '-',
|
||||
|
||||
(flags & kSCNetworkReachabilityFlagsConnectionRequired) ? 'c' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsTransientConnection) ? 't' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsInterventionRequired) ? 'i' : '-',
|
||||
// v3 kSCNetworkReachabilityFlagsConnectionOnTraffic == v2 kSCNetworkReachabilityFlagsConnectionAutomatic
|
||||
(flags & kSCNetworkReachabilityFlagsConnectionAutomatic) ? 'C' : '-',
|
||||
// (flags & kSCNetworkReachabilityFlagsConnectionOnDemand) ? 'D' : '-', // No v2 equivalent.
|
||||
(flags & kSCNetworkReachabilityFlagsIsLocalAddress) ? 'l' : '-',
|
||||
(flags & kSCNetworkReachabilityFlagsIsDirect) ? 'd' : '-'];
|
||||
#endif
|
||||
|
||||
} // reachabilityFlags_()
|
||||
|
||||
static void logReachabilityFlags_(const char *name, int line, SCNetworkReachabilityFlags flags) {
|
||||
|
||||
NSLog(@"%s (%d) \n\t%@", name, line, reachabilityFlags_(flags));
|
||||
|
||||
} // logReachabilityFlags_()
|
||||
|
||||
#define logNetworkStatus(status) (logNetworkStatus_(__PRETTY_FUNCTION__, __LINE__, status))
|
||||
|
||||
static void logNetworkStatus_(const char *name, int line, NetworkStatus status) {
|
||||
|
||||
NSString *statusString = nil;
|
||||
|
||||
switch (status) {
|
||||
case kNotReachable:
|
||||
statusString = @"Not Reachable";
|
||||
break;
|
||||
case kReachableViaWWAN:
|
||||
statusString = @"Reachable via WWAN";
|
||||
break;
|
||||
case kReachableViaWiFi:
|
||||
statusString = @"Reachable via WiFi";
|
||||
break;
|
||||
}
|
||||
|
||||
NSLog(@"%s (%d) \n\tNetwork Status: %@", name, line, statusString);
|
||||
|
||||
} // logNetworkStatus_()
|
||||
|
||||
#else
|
||||
#define logReachabilityFlags(flags)
|
||||
#define logNetworkStatus(status)
|
||||
#endif
|
||||
|
||||
@interface Reachability ()
|
||||
|
||||
- (NetworkStatus) networkStatusForFlags: (SCNetworkReachabilityFlags) flags;
|
||||
|
||||
@end
|
||||
|
||||
@implementation Reachability
|
||||
|
||||
@synthesize key = key_;
|
||||
|
||||
// Preclude direct access to ivars.
|
||||
+ (BOOL) accessInstanceVariablesDirectly {
|
||||
|
||||
return NO;
|
||||
|
||||
} // accessInstanceVariablesDirectly
|
||||
|
||||
|
||||
- (void) dealloc {
|
||||
|
||||
[self stopNotifier];
|
||||
if(reachabilityRef) {
|
||||
|
||||
CFRelease(reachabilityRef); reachabilityRef = NULL;
|
||||
|
||||
}
|
||||
|
||||
self.key = nil;
|
||||
|
||||
[super dealloc];
|
||||
|
||||
} // dealloc
|
||||
|
||||
|
||||
- (Reachability *) initWithReachabilityRef: (SCNetworkReachabilityRef) ref
|
||||
{
|
||||
self = [super init];
|
||||
if (self != nil)
|
||||
{
|
||||
reachabilityRef = ref;
|
||||
}
|
||||
|
||||
return self;
|
||||
|
||||
} // initWithReachabilityRef:
|
||||
|
||||
|
||||
#if (defined DEBUG && defined CLASS_DEBUG)
|
||||
- (NSString *) description {
|
||||
|
||||
NSAssert(reachabilityRef, @"-description called with NULL reachabilityRef");
|
||||
|
||||
SCNetworkReachabilityFlags flags = 0;
|
||||
|
||||
SCNetworkReachabilityGetFlags(reachabilityRef, &flags);
|
||||
|
||||
return [NSString stringWithFormat: @"%@\n\t%@", self.key, reachabilityFlags_(flags)];
|
||||
|
||||
} // description
|
||||
#endif
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Notification Management Methods
|
||||
|
||||
|
||||
//Start listening for reachability notifications on the current run loop
|
||||
static void ReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info) {
|
||||
|
||||
#pragma unused (target, flags)
|
||||
NSCAssert(info, @"info was NULL in ReachabilityCallback");
|
||||
NSCAssert([(NSObject*) info isKindOfClass: [Reachability class]], @"info was the wrong class in ReachabilityCallback");
|
||||
|
||||
//We're on the main RunLoop, so an NSAutoreleasePool is not necessary, but is added defensively
|
||||
// in case someone uses the Reachablity object in a different thread.
|
||||
NSAutoreleasePool* pool = [NSAutoreleasePool new];
|
||||
|
||||
// Post a notification to notify the client that the network reachability changed.
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName: kReachabilityChangedNotification
|
||||
object: (Reachability *) info];
|
||||
|
||||
[pool release];
|
||||
|
||||
} // ReachabilityCallback()
|
||||
|
||||
|
||||
- (BOOL) startNotifier {
|
||||
|
||||
SCNetworkReachabilityContext context = {0, self, NULL, NULL, NULL};
|
||||
|
||||
if(SCNetworkReachabilitySetCallback(reachabilityRef, ReachabilityCallback, &context)) {
|
||||
|
||||
if(SCNetworkReachabilityScheduleWithRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) {
|
||||
|
||||
return YES;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return NO;
|
||||
|
||||
} // startNotifier
|
||||
|
||||
|
||||
- (void) stopNotifier {
|
||||
|
||||
if(reachabilityRef) {
|
||||
|
||||
SCNetworkReachabilityUnscheduleFromRunLoop(reachabilityRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
||||
|
||||
}
|
||||
|
||||
} // stopNotifier
|
||||
|
||||
|
||||
- (BOOL) isEqual: (Reachability *) r {
|
||||
|
||||
return [r.key isEqualToString: self.key];
|
||||
|
||||
} // isEqual:
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Reachability Allocation Methods
|
||||
|
||||
|
||||
+ (Reachability *) reachabilityWithHostName: (NSString *) hostName {
|
||||
|
||||
SCNetworkReachabilityRef ref = SCNetworkReachabilityCreateWithName(NULL, [hostName UTF8String]);
|
||||
|
||||
if (ref) {
|
||||
|
||||
Reachability *r = [[[self alloc] initWithReachabilityRef: ref] autorelease];
|
||||
|
||||
r.key = hostName;
|
||||
|
||||
return r;
|
||||
|
||||
}
|
||||
|
||||
return nil;
|
||||
|
||||
} // reachabilityWithHostName
|
||||
|
||||
|
||||
+ (NSString *) makeAddressKey: (in_addr_t) addr {
|
||||
// addr is assumed to be in network byte order.
|
||||
|
||||
static const int highShift = 24;
|
||||
static const int highMidShift = 16;
|
||||
static const int lowMidShift = 8;
|
||||
static const in_addr_t mask = 0x000000ff;
|
||||
|
||||
addr = ntohl(addr);
|
||||
|
||||
return [NSString stringWithFormat: @"%d.%d.%d.%d",
|
||||
(addr >> highShift) & mask,
|
||||
(addr >> highMidShift) & mask,
|
||||
(addr >> lowMidShift) & mask,
|
||||
addr & mask];
|
||||
|
||||
} // makeAddressKey:
|
||||
|
||||
|
||||
+ (Reachability *) reachabilityWithAddress: (const struct sockaddr_in *) hostAddress {
|
||||
|
||||
SCNetworkReachabilityRef ref = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr*)hostAddress);
|
||||
|
||||
if (ref) {
|
||||
|
||||
Reachability *r = [[[self alloc] initWithReachabilityRef: ref] autorelease];
|
||||
|
||||
r.key = [self makeAddressKey: hostAddress->sin_addr.s_addr];
|
||||
|
||||
return r;
|
||||
|
||||
}
|
||||
|
||||
return nil;
|
||||
|
||||
} // reachabilityWithAddress
|
||||
|
||||
|
||||
+ (Reachability *) reachabilityForInternetConnection {
|
||||
|
||||
struct sockaddr_in zeroAddress;
|
||||
bzero(&zeroAddress, sizeof(zeroAddress));
|
||||
zeroAddress.sin_len = sizeof(zeroAddress);
|
||||
zeroAddress.sin_family = AF_INET;
|
||||
|
||||
Reachability *r = [self reachabilityWithAddress: &zeroAddress];
|
||||
|
||||
r.key = kInternetConnection;
|
||||
|
||||
return r;
|
||||
|
||||
} // reachabilityForInternetConnection
|
||||
|
||||
|
||||
+ (Reachability *) reachabilityForLocalWiFi {
|
||||
|
||||
struct sockaddr_in localWifiAddress;
|
||||
bzero(&localWifiAddress, sizeof(localWifiAddress));
|
||||
localWifiAddress.sin_len = sizeof(localWifiAddress);
|
||||
localWifiAddress.sin_family = AF_INET;
|
||||
// IN_LINKLOCALNETNUM is defined in <netinet/in.h> as 169.254.0.0
|
||||
localWifiAddress.sin_addr.s_addr = htonl(IN_LINKLOCALNETNUM);
|
||||
|
||||
Reachability *r = [self reachabilityWithAddress: &localWifiAddress];
|
||||
|
||||
r.key = kLocalWiFiConnection;
|
||||
|
||||
return r;
|
||||
|
||||
} // reachabilityForLocalWiFi
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Network Flag Handling Methods
|
||||
|
||||
|
||||
#if USE_DDG_EXTENSIONS
|
||||
//
|
||||
// iPhone condition codes as reported by a 3GS running iPhone OS v3.0.
|
||||
// Airplane Mode turned on: Reachability Flag Status: -- -------
|
||||
// WWAN Active: Reachability Flag Status: WR -t-----
|
||||
// WWAN Connection required: Reachability Flag Status: WR ct-----
|
||||
// WiFi turned on: Reachability Flag Status: -R ------- Reachable.
|
||||
// Local WiFi turned on: Reachability Flag Status: -R xxxxxxd Reachable.
|
||||
// WiFi turned on: Reachability Flag Status: -R ct----- Connection down. (Non-intuitive, empirically determined answer.)
|
||||
const SCNetworkReachabilityFlags kConnectionDown = kSCNetworkReachabilityFlagsConnectionRequired |
|
||||
kSCNetworkReachabilityFlagsTransientConnection;
|
||||
// WiFi turned on: Reachability Flag Status: -R ct-i--- Reachable but it will require user intervention (e.g. enter a WiFi password).
|
||||
// WiFi turned on: Reachability Flag Status: -R -t----- Reachable via VPN.
|
||||
//
|
||||
// In the below method, an 'x' in the flag status means I don't care about its value.
|
||||
//
|
||||
// This method differs from Apple's by testing explicitly for empirically observed values.
|
||||
// This gives me more confidence in it's correct behavior. Apple's code covers more cases
|
||||
// than mine. My code covers the cases that occur.
|
||||
//
|
||||
- (NetworkStatus) networkStatusForFlags: (SCNetworkReachabilityFlags) flags {
|
||||
|
||||
if (flags & kSCNetworkReachabilityFlagsReachable) {
|
||||
|
||||
// Local WiFi -- Test derived from Apple's code: -localWiFiStatusForFlags:.
|
||||
if (self.key == kLocalWiFiConnection) {
|
||||
|
||||
// Reachability Flag Status: xR xxxxxxd Reachable.
|
||||
return (flags & kSCNetworkReachabilityFlagsIsDirect) ? kReachableViaWiFi : kNotReachable;
|
||||
|
||||
}
|
||||
|
||||
// Observed WWAN Values:
|
||||
// WWAN Active: Reachability Flag Status: WR -t-----
|
||||
// WWAN Connection required: Reachability Flag Status: WR ct-----
|
||||
//
|
||||
// Test Value: Reachability Flag Status: WR xxxxxxx
|
||||
if (flags & kSCNetworkReachabilityFlagsIsWWAN) { return kReachableViaWWAN; }
|
||||
|
||||
// Clear moot bits.
|
||||
flags &= ~kSCNetworkReachabilityFlagsReachable;
|
||||
flags &= ~kSCNetworkReachabilityFlagsIsDirect;
|
||||
flags &= ~kSCNetworkReachabilityFlagsIsLocalAddress; // kInternetConnection is local.
|
||||
|
||||
// Reachability Flag Status: -R ct---xx Connection down.
|
||||
if (flags == kConnectionDown) { return kNotReachable; }
|
||||
|
||||
// Reachability Flag Status: -R -t---xx Reachable. WiFi + VPN(is up) (Thank you Ling Wang)
|
||||
if (flags & kSCNetworkReachabilityFlagsTransientConnection) { return kReachableViaWiFi; }
|
||||
|
||||
// Reachability Flag Status: -R -----xx Reachable.
|
||||
if (flags == 0) { return kReachableViaWiFi; }
|
||||
|
||||
// Apple's code tests for dynamic connection types here. I don't.
|
||||
// If a connection is required, regardless of whether it is on demand or not, it is a WiFi connection.
|
||||
// If you care whether a connection needs to be brought up, use -isConnectionRequired.
|
||||
// If you care about whether user intervention is necessary, use -isInterventionRequired.
|
||||
// If you care about dynamically establishing the connection, use -isConnectionIsOnDemand.
|
||||
|
||||
// Reachability Flag Status: -R cxxxxxx Reachable.
|
||||
if (flags & kSCNetworkReachabilityFlagsConnectionRequired) { return kReachableViaWiFi; }
|
||||
|
||||
// Required by the compiler. Should never get here. Default to not connected.
|
||||
#if (defined DEBUG && defined CLASS_DEBUG)
|
||||
NSAssert1(NO, @"Uncaught reachability test. Flags: %@", reachabilityFlags_(flags));
|
||||
#endif
|
||||
return kNotReachable;
|
||||
|
||||
}
|
||||
|
||||
// Reachability Flag Status: x- xxxxxxx
|
||||
return kNotReachable;
|
||||
|
||||
} // networkStatusForFlags:
|
||||
|
||||
|
||||
- (NetworkStatus) currentReachabilityStatus {
|
||||
|
||||
NSAssert(reachabilityRef, @"currentReachabilityStatus called with NULL reachabilityRef");
|
||||
|
||||
SCNetworkReachabilityFlags flags = 0;
|
||||
NetworkStatus status = kNotReachable;
|
||||
|
||||
if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) {
|
||||
|
||||
// logReachabilityFlags(flags);
|
||||
|
||||
status = [self networkStatusForFlags: flags];
|
||||
|
||||
return status;
|
||||
|
||||
}
|
||||
|
||||
return kNotReachable;
|
||||
|
||||
} // currentReachabilityStatus
|
||||
|
||||
|
||||
- (BOOL) isReachable {
|
||||
|
||||
NSAssert(reachabilityRef, @"isReachable called with NULL reachabilityRef");
|
||||
|
||||
SCNetworkReachabilityFlags flags = 0;
|
||||
NetworkStatus status = kNotReachable;
|
||||
|
||||
if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) {
|
||||
|
||||
// logReachabilityFlags(flags);
|
||||
|
||||
status = [self networkStatusForFlags: flags];
|
||||
|
||||
// logNetworkStatus(status);
|
||||
|
||||
return (kNotReachable != status);
|
||||
|
||||
}
|
||||
|
||||
return NO;
|
||||
|
||||
} // isReachable
|
||||
|
||||
|
||||
- (BOOL) isConnectionRequired {
|
||||
|
||||
NSAssert(reachabilityRef, @"isConnectionRequired called with NULL reachabilityRef");
|
||||
|
||||
SCNetworkReachabilityFlags flags;
|
||||
|
||||
if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) {
|
||||
|
||||
logReachabilityFlags(flags);
|
||||
|
||||
return (flags & kSCNetworkReachabilityFlagsConnectionRequired);
|
||||
|
||||
}
|
||||
|
||||
return NO;
|
||||
|
||||
} // isConnectionRequired
|
||||
|
||||
|
||||
- (BOOL) connectionRequired {
|
||||
|
||||
return [self isConnectionRequired];
|
||||
|
||||
} // connectionRequired
|
||||
#endif
|
||||
|
||||
|
||||
#if (__IPHONE_OS_VERSION_MIN_REQUIRED >= 30000)
|
||||
static const SCNetworkReachabilityFlags kOnDemandConnection = kSCNetworkReachabilityFlagsConnectionOnTraffic |
|
||||
kSCNetworkReachabilityFlagsConnectionOnDemand;
|
||||
#else
|
||||
static const SCNetworkReachabilityFlags kOnDemandConnection = kSCNetworkReachabilityFlagsConnectionAutomatic;
|
||||
#endif
|
||||
|
||||
- (BOOL) isConnectionOnDemand {
|
||||
|
||||
NSAssert(reachabilityRef, @"isConnectionIsOnDemand called with NULL reachabilityRef");
|
||||
|
||||
SCNetworkReachabilityFlags flags;
|
||||
|
||||
if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) {
|
||||
|
||||
logReachabilityFlags(flags);
|
||||
|
||||
return ((flags & kSCNetworkReachabilityFlagsConnectionRequired) &&
|
||||
(flags & kOnDemandConnection));
|
||||
|
||||
}
|
||||
|
||||
return NO;
|
||||
|
||||
} // isConnectionOnDemand
|
||||
|
||||
|
||||
- (BOOL) isInterventionRequired {
|
||||
|
||||
NSAssert(reachabilityRef, @"isInterventionRequired called with NULL reachabilityRef");
|
||||
|
||||
SCNetworkReachabilityFlags flags;
|
||||
|
||||
if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) {
|
||||
|
||||
logReachabilityFlags(flags);
|
||||
|
||||
return ((flags & kSCNetworkReachabilityFlagsConnectionRequired) &&
|
||||
(flags & kSCNetworkReachabilityFlagsInterventionRequired));
|
||||
|
||||
}
|
||||
|
||||
return NO;
|
||||
|
||||
} // isInterventionRequired
|
||||
|
||||
|
||||
- (BOOL) isReachableViaWWAN {
|
||||
|
||||
NSAssert(reachabilityRef, @"isReachableViaWWAN called with NULL reachabilityRef");
|
||||
|
||||
SCNetworkReachabilityFlags flags = 0;
|
||||
NetworkStatus status = kNotReachable;
|
||||
|
||||
if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) {
|
||||
|
||||
logReachabilityFlags(flags);
|
||||
|
||||
status = [self networkStatusForFlags: flags];
|
||||
|
||||
return (kReachableViaWWAN == status);
|
||||
|
||||
}
|
||||
|
||||
return NO;
|
||||
|
||||
} // isReachableViaWWAN
|
||||
|
||||
|
||||
- (BOOL) isReachableViaWiFi {
|
||||
|
||||
NSAssert(reachabilityRef, @"isReachableViaWiFi called with NULL reachabilityRef");
|
||||
|
||||
SCNetworkReachabilityFlags flags = 0;
|
||||
NetworkStatus status = kNotReachable;
|
||||
|
||||
if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) {
|
||||
|
||||
logReachabilityFlags(flags);
|
||||
|
||||
status = [self networkStatusForFlags: flags];
|
||||
|
||||
return (kReachableViaWiFi == status);
|
||||
|
||||
}
|
||||
|
||||
return NO;
|
||||
|
||||
} // isReachableViaWiFi
|
||||
|
||||
|
||||
- (SCNetworkReachabilityFlags) reachabilityFlags {
|
||||
|
||||
NSAssert(reachabilityRef, @"reachabilityFlags called with NULL reachabilityRef");
|
||||
|
||||
SCNetworkReachabilityFlags flags = 0;
|
||||
|
||||
if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) {
|
||||
|
||||
logReachabilityFlags(flags);
|
||||
|
||||
return flags;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
} // reachabilityFlags
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Apple's Network Flag Handling Methods
|
||||
|
||||
|
||||
#if !USE_DDG_EXTENSIONS
|
||||
/*
|
||||
*
|
||||
* Apple's Network Status testing code.
|
||||
* The only changes that have been made are to use the new logReachabilityFlags macro and
|
||||
* test for local WiFi via the key instead of Apple's boolean. Also, Apple's code was for v3.0 only
|
||||
* iPhone OS. v2.2.1 and earlier conditional compiling is turned on. Hence, to mirror Apple's behavior,
|
||||
* set your Base SDK to v3.0 or higher.
|
||||
*
|
||||
*/
|
||||
|
||||
- (NetworkStatus) localWiFiStatusForFlags: (SCNetworkReachabilityFlags) flags
|
||||
{
|
||||
logReachabilityFlags(flags);
|
||||
|
||||
BOOL retVal = NotReachable;
|
||||
if((flags & kSCNetworkReachabilityFlagsReachable) && (flags & kSCNetworkReachabilityFlagsIsDirect))
|
||||
{
|
||||
retVal = ReachableViaWiFi;
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
- (NetworkStatus) networkStatusForFlags: (SCNetworkReachabilityFlags) flags
|
||||
{
|
||||
logReachabilityFlags(flags);
|
||||
if (!(flags & kSCNetworkReachabilityFlagsReachable))
|
||||
{
|
||||
// if target host is not reachable
|
||||
return NotReachable;
|
||||
}
|
||||
|
||||
BOOL retVal = NotReachable;
|
||||
|
||||
if (!(flags & kSCNetworkReachabilityFlagsConnectionRequired))
|
||||
{
|
||||
// if target host is reachable and no connection is required
|
||||
// then we'll assume (for now) that your on Wi-Fi
|
||||
retVal = ReachableViaWiFi;
|
||||
}
|
||||
|
||||
#if (__IPHONE_OS_VERSION_MIN_REQUIRED >= 30000) // Apple advises you to use the magic number instead of a symbol.
|
||||
if ((flags & kSCNetworkReachabilityFlagsConnectionOnDemand) ||
|
||||
(flags & kSCNetworkReachabilityFlagsConnectionOnTraffic))
|
||||
#else
|
||||
if (flags & kSCNetworkReachabilityFlagsConnectionAutomatic)
|
||||
#endif
|
||||
{
|
||||
// ... and the connection is on-demand (or on-traffic) if the
|
||||
// calling application is using the CFSocketStream or higher APIs
|
||||
|
||||
if (!(flags & kSCNetworkReachabilityFlagsInterventionRequired))
|
||||
{
|
||||
// ... and no [user] intervention is needed
|
||||
retVal = ReachableViaWiFi;
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & kSCNetworkReachabilityFlagsIsWWAN)
|
||||
{
|
||||
// ... but WWAN connections are OK if the calling application
|
||||
// is using the CFNetwork (CFSocketStream?) APIs.
|
||||
retVal = ReachableViaWWAN;
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
- (NetworkStatus) currentReachabilityStatus
|
||||
{
|
||||
NSAssert(reachabilityRef, @"currentReachabilityStatus called with NULL reachabilityRef");
|
||||
|
||||
NetworkStatus retVal = NotReachable;
|
||||
SCNetworkReachabilityFlags flags;
|
||||
if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags))
|
||||
{
|
||||
if(self.key == kLocalWiFiConnection)
|
||||
{
|
||||
retVal = [self localWiFiStatusForFlags: flags];
|
||||
}
|
||||
else
|
||||
{
|
||||
retVal = [self networkStatusForFlags: flags];
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL) isReachable {
|
||||
|
||||
NSAssert(reachabilityRef, @"isReachable called with NULL reachabilityRef");
|
||||
|
||||
SCNetworkReachabilityFlags flags = 0;
|
||||
NetworkStatus status = kNotReachable;
|
||||
|
||||
if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) {
|
||||
|
||||
logReachabilityFlags(flags);
|
||||
|
||||
if(self.key == kLocalWiFiConnection) {
|
||||
|
||||
status = [self localWiFiStatusForFlags: flags];
|
||||
|
||||
} else {
|
||||
|
||||
status = [self networkStatusForFlags: flags];
|
||||
|
||||
}
|
||||
|
||||
return (kNotReachable != status);
|
||||
|
||||
}
|
||||
|
||||
return NO;
|
||||
|
||||
} // isReachable
|
||||
|
||||
|
||||
- (BOOL) isConnectionRequired {
|
||||
|
||||
return [self connectionRequired];
|
||||
|
||||
} // isConnectionRequired
|
||||
|
||||
|
||||
- (BOOL) connectionRequired {
|
||||
|
||||
NSAssert(reachabilityRef, @"connectionRequired called with NULL reachabilityRef");
|
||||
|
||||
SCNetworkReachabilityFlags flags;
|
||||
|
||||
if (SCNetworkReachabilityGetFlags(reachabilityRef, &flags)) {
|
||||
|
||||
logReachabilityFlags(flags);
|
||||
|
||||
return (flags & kSCNetworkReachabilityFlagsConnectionRequired);
|
||||
|
||||
}
|
||||
|
||||
return NO;
|
||||
|
||||
} // connectionRequired
|
||||
#endif
|
||||
|
||||
@end
|
||||
9
msext/Class/Common/AppID.h
Executable file
9
msext/Class/Common/AppID.h
Executable file
@@ -0,0 +1,9 @@
|
||||
//
|
||||
// AppID.h
|
||||
// Agora iOS Tutorial Objective-C
|
||||
//
|
||||
// Created by James Fang on 7/19/16.
|
||||
// Copyright © 2016 Agora.io. All rights reserved.
|
||||
//
|
||||
|
||||
FOUNDATION_EXPORT NSString *const appID;
|
||||
11
msext/Class/Common/AppID.m
Executable file
11
msext/Class/Common/AppID.m
Executable file
@@ -0,0 +1,11 @@
|
||||
//
|
||||
// AppID.m
|
||||
// Agora iOS Tutorial Objective-C
|
||||
//
|
||||
// Created by James Fang on 7/19/16.
|
||||
// Copyright © 2016 Agora.io. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NSString *const appID = @"ad97e1945b1e4fb5ad5b5246c8ca21e4"; // Tutorial Step 1
|
||||
BIN
msext/Class/Common/Bugly.framework/Bugly
Executable file
BIN
msext/Class/Common/Bugly.framework/Bugly
Executable file
Binary file not shown.
142
msext/Class/Common/Bugly.framework/Headers/Bugly.h
Executable file
142
msext/Class/Common/Bugly.framework/Headers/Bugly.h
Executable file
@@ -0,0 +1,142 @@
|
||||
//
|
||||
// Bugly.h
|
||||
// Bugly
|
||||
//
|
||||
// Version: 2.4(8)
|
||||
//
|
||||
// Copyright (c) 2016年 Bugly. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "BuglyConfig.h"
|
||||
#import "BuglyLog.h"
|
||||
|
||||
BLY_START_NONNULL
|
||||
|
||||
@interface Bugly : NSObject
|
||||
|
||||
/**
|
||||
* 初始化Bugly,使用默认BuglyConfig
|
||||
*
|
||||
* @param appId 注册Bugly分配的应用唯一标识
|
||||
*/
|
||||
+ (void)startWithAppId:(NSString * BLY_NULLABLE)appId;
|
||||
|
||||
/**
|
||||
* 使用指定配置初始化Bugly
|
||||
*
|
||||
* @param appId 注册Bugly分配的应用唯一标识
|
||||
* @param config 传入配置的 BuglyConfig
|
||||
*/
|
||||
+ (void)startWithAppId:(NSString * BLY_NULLABLE)appId
|
||||
config:(BuglyConfig * BLY_NULLABLE)config;
|
||||
|
||||
/**
|
||||
* 使用指定配置初始化Bugly
|
||||
*
|
||||
* @param appId 注册Bugly分配的应用唯一标识
|
||||
* @param development 是否开发设备
|
||||
* @param config 传入配置的 BuglyConfig
|
||||
*/
|
||||
+ (void)startWithAppId:(NSString * BLY_NULLABLE)appId
|
||||
developmentDevice:(BOOL)development
|
||||
config:(BuglyConfig * BLY_NULLABLE)config;
|
||||
|
||||
/**
|
||||
* 设置用户标识
|
||||
*
|
||||
* @param userId 用户标识
|
||||
*/
|
||||
+ (void)setUserIdentifier:(NSString *)userId;
|
||||
|
||||
/**
|
||||
* 更新版本信息
|
||||
*
|
||||
* @param version 应用版本信息
|
||||
*/
|
||||
+ (void)updateAppVersion:(NSString *)version;
|
||||
|
||||
/**
|
||||
* 设置关键数据,随崩溃信息上报
|
||||
*
|
||||
* @param value KEY
|
||||
* @param key VALUE
|
||||
*/
|
||||
+ (void)setUserValue:(NSString *)value
|
||||
forKey:(NSString *)key;
|
||||
|
||||
/**
|
||||
* 获取关键数据
|
||||
*
|
||||
* @return 关键数据
|
||||
*/
|
||||
+ (NSDictionary * BLY_NULLABLE)allUserValues;
|
||||
|
||||
/**
|
||||
* 设置标签
|
||||
*
|
||||
* @param tag 标签ID,可在网站生成
|
||||
*/
|
||||
+ (void)setTag:(NSUInteger)tag;
|
||||
|
||||
/**
|
||||
* 获取当前设置标签
|
||||
*
|
||||
* @return 当前标签ID
|
||||
*/
|
||||
+ (NSUInteger)currentTag;
|
||||
|
||||
/**
|
||||
* 获取设备ID
|
||||
*
|
||||
* @return 设备ID
|
||||
*/
|
||||
+ (NSString *)buglyDeviceId;
|
||||
|
||||
/**
|
||||
* 上报自定义Objective-C异常
|
||||
*
|
||||
* @param exception 异常信息
|
||||
*/
|
||||
+ (void)reportException:(NSException *)exception;
|
||||
|
||||
/**
|
||||
* 上报错误
|
||||
*
|
||||
* @param error 错误信息
|
||||
*/
|
||||
+ (void)reportError:(NSError *)error;
|
||||
|
||||
/**
|
||||
* @brief 上报自定义错误
|
||||
*
|
||||
* @param category 类型(Cocoa=3,CSharp=4,JS=5,Lua=6)
|
||||
* @param aName 名称
|
||||
* @param aReason 错误原因
|
||||
* @param aStackArray 堆栈
|
||||
* @param info 附加数据
|
||||
* @param terminate 上报后是否退出应用进程
|
||||
*/
|
||||
+ (void)reportExceptionWithCategory:(NSUInteger)category name:(NSString *)aName reason:(NSString *)aReason callStack:(NSArray *)aStackArray extraInfo:(NSDictionary *)info terminateApp:(BOOL)terminate;
|
||||
|
||||
/**
|
||||
* SDK 版本信息
|
||||
*
|
||||
* @return SDK版本号
|
||||
*/
|
||||
+ (NSString *)sdkVersion;
|
||||
|
||||
/**
|
||||
* App 是否发生了连续闪退
|
||||
* 如果启动SDK 且 5秒内 闪退,且次数达到 3次 则判定为连续闪退
|
||||
*
|
||||
* @return 是否连续闪退
|
||||
*/
|
||||
+ (BOOL)isAppCrashedOnStartUpExceedTheLimit;
|
||||
|
||||
+ (void)setComponentIdentifier:(NSString *)componentId version:(NSString *)version;
|
||||
|
||||
BLY_END_NONNULL
|
||||
|
||||
@end
|
||||
118
msext/Class/Common/Bugly.framework/Headers/BuglyConfig.h
Executable file
118
msext/Class/Common/Bugly.framework/Headers/BuglyConfig.h
Executable file
@@ -0,0 +1,118 @@
|
||||
//
|
||||
// BuglyConfig.h
|
||||
//
|
||||
//
|
||||
// Copyright (c) 2016年 Tencent. All rights reserved.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#define BLY_UNAVAILABLE(x) __attribute__((unavailable(x)))
|
||||
|
||||
#if __has_feature(nullability)
|
||||
#define BLY_NONNULL __nonnull
|
||||
#define BLY_NULLABLE __nullable
|
||||
#define BLY_START_NONNULL _Pragma("clang assume_nonnull begin")
|
||||
#define BLY_END_NONNULL _Pragma("clang assume_nonnull end")
|
||||
#else
|
||||
#define BLY_NONNULL
|
||||
#define BLY_NULLABLE
|
||||
#define BLY_START_NONNULL
|
||||
#define BLY_END_NONNULL
|
||||
#endif
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "BuglyLog.h"
|
||||
|
||||
BLY_START_NONNULL
|
||||
|
||||
@protocol BuglyDelegate <NSObject>
|
||||
|
||||
@optional
|
||||
/**
|
||||
* 发生异常时回调
|
||||
*
|
||||
* @param exception 异常信息
|
||||
*
|
||||
* @return 返回需上报记录,随异常上报一起上报
|
||||
*/
|
||||
- (NSString * BLY_NULLABLE)attachmentForException:(NSException * BLY_NULLABLE)exception;
|
||||
|
||||
@end
|
||||
|
||||
@interface BuglyConfig : NSObject
|
||||
|
||||
/**
|
||||
* SDK Debug信息开关, 默认关闭
|
||||
*/
|
||||
@property (nonatomic, assign) BOOL debugMode;
|
||||
|
||||
/**
|
||||
* 设置自定义渠道标识
|
||||
*/
|
||||
@property (nonatomic, copy) NSString *channel;
|
||||
|
||||
/**
|
||||
* 设置自定义版本号
|
||||
*/
|
||||
@property (nonatomic, copy) NSString *version;
|
||||
|
||||
/**
|
||||
* 设置自定义设备唯一标识
|
||||
*/
|
||||
@property (nonatomic, copy) NSString *deviceIdentifier;
|
||||
|
||||
/**
|
||||
* 卡顿监控开关,默认关闭
|
||||
*/
|
||||
@property (nonatomic) BOOL blockMonitorEnable;
|
||||
|
||||
/**
|
||||
* 卡顿监控判断间隔,单位为秒
|
||||
*/
|
||||
@property (nonatomic) NSTimeInterval blockMonitorTimeout;
|
||||
|
||||
/**
|
||||
* 设置 App Groups Id (如有使用 Bugly iOS Extension SDK,请设置该值)
|
||||
*/
|
||||
@property (nonatomic, copy) NSString *applicationGroupIdentifier;
|
||||
|
||||
/**
|
||||
* 进程内还原开关,默认开启
|
||||
*/
|
||||
@property (nonatomic) BOOL symbolicateInProcessEnable;
|
||||
|
||||
/**
|
||||
* 非正常退出事件记录开关,默认关闭
|
||||
*/
|
||||
@property (nonatomic) BOOL unexpectedTerminatingDetectionEnable;
|
||||
|
||||
/**
|
||||
* 页面信息记录开关,默认开启
|
||||
*/
|
||||
@property (nonatomic) BOOL viewControllerTrackingEnable;
|
||||
|
||||
/**
|
||||
* Bugly Delegate
|
||||
*/
|
||||
@property (nonatomic, assign) id<BuglyDelegate> delegate;
|
||||
|
||||
/**
|
||||
* 控制自定义日志上报,默认值为BuglyLogLevelSilent,即关闭日志记录功能。
|
||||
* 如果设置为BuglyLogLevelWarn,则在崩溃时会上报Warn、Error接口打印的日志
|
||||
*/
|
||||
@property (nonatomic, assign) BuglyLogLevel reportLogLevel;
|
||||
|
||||
/**
|
||||
* 崩溃数据过滤器,如果崩溃堆栈的模块名包含过滤器中设置的关键字,则崩溃数据不会进行上报
|
||||
* 例如,过滤崩溃堆栈中包含搜狗输入法的数据,可以添加过滤器关键字SogouInputIPhone.dylib等
|
||||
*/
|
||||
@property (nonatomic, copy) NSArray *excludeModuleFilter;
|
||||
|
||||
/**
|
||||
* 控制台日志上报开关,默认开启
|
||||
*/
|
||||
@property (nonatomic, assign) BOOL consolelogEnable;
|
||||
|
||||
@end
|
||||
BLY_END_NONNULL
|
||||
77
msext/Class/Common/Bugly.framework/Headers/BuglyLog.h
Executable file
77
msext/Class/Common/Bugly.framework/Headers/BuglyLog.h
Executable file
@@ -0,0 +1,77 @@
|
||||
//
|
||||
// BuglyLog.h
|
||||
//
|
||||
// Copyright © 2017 tencent.com. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
// Log level for Bugly Log
|
||||
typedef NS_ENUM(NSUInteger, BuglyLogLevel) {
|
||||
BuglyLogLevelSilent = 0,
|
||||
BuglyLogLevelError = 1,
|
||||
BuglyLogLevelWarn = 2,
|
||||
BuglyLogLevelInfo = 3,
|
||||
BuglyLogLevelDebug = 4,
|
||||
BuglyLogLevelVerbose = 5,
|
||||
};
|
||||
#pragma mark -
|
||||
|
||||
OBJC_EXTERN void BLYLog(BuglyLogLevel level, NSString *format, ...) NS_FORMAT_FUNCTION(2, 3);
|
||||
|
||||
OBJC_EXTERN void BLYLogv(BuglyLogLevel level, NSString *format, va_list args) NS_FORMAT_FUNCTION(2, 0);
|
||||
|
||||
#pragma mark -
|
||||
#define BUGLY_LOG_MACRO(_level, fmt, ...) [BuglyLog level:_level tag:nil log:fmt, ##__VA_ARGS__]
|
||||
|
||||
#define BLYLogError(fmt, ...) BUGLY_LOG_MACRO(BuglyLogLevelError, fmt, ##__VA_ARGS__)
|
||||
#define BLYLogWarn(fmt, ...) BUGLY_LOG_MACRO(BuglyLogLevelWarn, fmt, ##__VA_ARGS__)
|
||||
#define BLYLogInfo(fmt, ...) BUGLY_LOG_MACRO(BuglyLogLevelInfo, fmt, ##__VA_ARGS__)
|
||||
#define BLYLogDebug(fmt, ...) BUGLY_LOG_MACRO(BuglyLogLevelDebug, fmt, ##__VA_ARGS__)
|
||||
#define BLYLogVerbose(fmt, ...) BUGLY_LOG_MACRO(BuglyLogLevelVerbose, fmt, ##__VA_ARGS__)
|
||||
|
||||
#pragma mark - Interface
|
||||
@interface BuglyLog : NSObject
|
||||
|
||||
/**
|
||||
* @brief 初始化日志模块
|
||||
*
|
||||
* @param level 设置默认日志级别,默认BLYLogLevelSilent
|
||||
*
|
||||
* @param printConsole 是否打印到控制台,默认NO
|
||||
*/
|
||||
+ (void)initLogger:(BuglyLogLevel) level consolePrint:(BOOL)printConsole;
|
||||
|
||||
/**
|
||||
* @brief 打印BLYLogLevelInfo日志
|
||||
*
|
||||
* @param format 日志内容 总日志大小限制为:字符串长度30k,条数200
|
||||
*/
|
||||
+ (void)log:(NSString *)format, ... NS_FORMAT_FUNCTION(1, 2);
|
||||
|
||||
/**
|
||||
* @brief 打印日志
|
||||
*
|
||||
* @param level 日志级别
|
||||
* @param message 日志内容 总日志大小限制为:字符串长度30k,条数200
|
||||
*/
|
||||
+ (void)level:(BuglyLogLevel) level logs:(NSString *)message;
|
||||
|
||||
/**
|
||||
* @brief 打印日志
|
||||
*
|
||||
* @param level 日志级别
|
||||
* @param format 日志内容 总日志大小限制为:字符串长度30k,条数200
|
||||
*/
|
||||
+ (void)level:(BuglyLogLevel) level log:(NSString *)format, ... NS_FORMAT_FUNCTION(2, 3);
|
||||
|
||||
/**
|
||||
* @brief 打印日志
|
||||
*
|
||||
* @param level 日志级别
|
||||
* @param tag 日志模块分类
|
||||
* @param format 日志内容 总日志大小限制为:字符串长度30k,条数200
|
||||
*/
|
||||
+ (void)level:(BuglyLogLevel) level tag:(NSString *) tag log:(NSString *)format, ... NS_FORMAT_FUNCTION(3, 4);
|
||||
|
||||
@end
|
||||
12
msext/Class/Common/Bugly.framework/Modules/module.modulemap
Executable file
12
msext/Class/Common/Bugly.framework/Modules/module.modulemap
Executable file
@@ -0,0 +1,12 @@
|
||||
framework module Bugly {
|
||||
umbrella header "Bugly.h"
|
||||
|
||||
export *
|
||||
module * { export * }
|
||||
|
||||
link framework "Foundation"
|
||||
link framework "Security"
|
||||
link framework "SystemConfiguration"
|
||||
link "c++"
|
||||
link "z"
|
||||
}
|
||||
295
msext/Class/Common/FuncPublic.h
Executable file
295
msext/Class/Common/FuncPublic.h
Executable file
@@ -0,0 +1,295 @@
|
||||
//
|
||||
// FuncPublic.h
|
||||
// MaiTian
|
||||
//
|
||||
// Created by 谌 安 on 13-3-1.
|
||||
// Copyright (c) 2013年 MaiTian. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
|
||||
@interface FuncPublic : NSObject
|
||||
{
|
||||
UIActivityIndicatorView* spin; //风火轮
|
||||
NSMutableArray* _NavigationArray; //所有navigation保存数组
|
||||
int _CurrentShowNavigationIndex;//当前所显示的界面 0:home界面
|
||||
|
||||
BOOL _IsHomeEnter; //是否从主页进入
|
||||
|
||||
BOOL flag;// onceShow;
|
||||
|
||||
UIViewController *currentVC_;
|
||||
}
|
||||
@property(nonatomic,retain)UIActivityIndicatorView* spin;
|
||||
@property(nonatomic,retain)NSMutableArray* _NavigationArray;
|
||||
@property(nonatomic,assign)int _CurrentShowNavigationIndex;
|
||||
@property(nonatomic,assign)int _CurrentShow;
|
||||
@property(nonatomic,assign)BOOL flag;
|
||||
@property(nonatomic,assign)BOOL _IsHomeEnter;
|
||||
@property(nonatomic,retain)UIImageView* LoadImage;
|
||||
@property(nonatomic,retain)UIViewController *currentVC;
|
||||
|
||||
+(FuncPublic*)SharedFuncPublic;
|
||||
#pragma mark 打开及关闭风火轮
|
||||
-(void)StartActivityAnimation:(UIViewController*)target;
|
||||
-(void)StopActivityAnimation;
|
||||
#pragma mark 打开及关闭风火轮 end------------
|
||||
#pragma mark 下工具栏-----------------
|
||||
|
||||
/*
|
||||
滑屏手势
|
||||
_view:需要移动的视图
|
||||
vc_:控制视图
|
||||
sel:移动完成后返回的方法
|
||||
status:状态 0:表示右 气态左
|
||||
*/
|
||||
-(void)UISwipeGestrue_Direction:(UIView *)view_ controllerview:(UIViewController *)vc_ Direction:(int)status SEL:(SEL)_sel;
|
||||
/*
|
||||
*获得机型宽高
|
||||
*/
|
||||
+(CGRect)GetSceneRect;
|
||||
/*
|
||||
*将控件添加到windows上 控件的x坐标需要设定为-100
|
||||
*view:需要添加到windows上面。显示在最上面的view
|
||||
*/
|
||||
+(void)ViewAddToWindows:(UIView*)view;
|
||||
+ (CGAffineTransform)transformForOrientation;
|
||||
/*
|
||||
*保存default信息
|
||||
*srt:需保存的文字
|
||||
*key:关键字
|
||||
*/
|
||||
+(void)SaveDefaultInfo:(id)str Key:(NSString*)_key;
|
||||
/*
|
||||
*获得保存default信息
|
||||
*key:关键字
|
||||
*/
|
||||
+(id)GetDefaultInfo:(NSString*)_key;
|
||||
/*
|
||||
* str:需显示的信息
|
||||
*/
|
||||
+(void)ShowAlert:(NSString*)str;
|
||||
/*
|
||||
* _path = 路径
|
||||
*/
|
||||
+(NSString*)GetNewPhotoUrl:(NSString*)_path;
|
||||
/*
|
||||
* name:文件名
|
||||
* ext:后缀
|
||||
*/
|
||||
+(UIImage*)CreatedImageFromFile:(NSString *)name ofType:(NSString *)ext;
|
||||
|
||||
/*
|
||||
* 通过iphone的坐标得到 与误差坐标,得到 二个值
|
||||
* IphoneRect:最初坐标
|
||||
* num:误差值
|
||||
* _kind: 1:X变 2:y变 3:w变 4: h变 5:x w 变 6: y h 变
|
||||
*/
|
||||
+(CGRect)Iphone5OrIphone4:(CGRect)IphoneRect Num:(float)_num Kind:(int)_kind;
|
||||
/*
|
||||
*通过尺寸获得size
|
||||
* IphoneSize:最初坐标
|
||||
* num:误差值
|
||||
* _kind: 1:w变 2:h变
|
||||
*/
|
||||
+(CGSize)SizeByIphone:(CGSize)IphoneSize Num:(float)_num Kind:(int)_kind;
|
||||
|
||||
/*
|
||||
* 实例image
|
||||
*FileNmae:图片文件名
|
||||
*ect:图片后缀名
|
||||
*_rect:位置
|
||||
*target:父类
|
||||
*_index:tag
|
||||
*
|
||||
*/
|
||||
+(UIImageView*)InstanceImageView:(NSString*)FileName FileName5:(NSString*)FileName5 Ect:(NSString*)ect RECT:(CGRect)_rect RECT5:(CGRect)_rect5 Target:(id)target TAG:(int)_index;
|
||||
|
||||
/*
|
||||
* 攻能:图片等比例缩放,上下左右留白
|
||||
* size:缩放的width,height
|
||||
* _pimage:需要改变的图片
|
||||
*/
|
||||
+(UIImage*)scaleToSize:(CGSize)size ParentImage:(UIImage*)_PImage;
|
||||
/*
|
||||
*FileNmae:正常状态按键文件名
|
||||
*ect:正常状态按键后缀名
|
||||
*
|
||||
*FileName2:按下状态文件名
|
||||
*ect2:按下状态后缀名
|
||||
*AddView:需要添加到的view,(有时可能直接需要view,所以增加了vc,用来做delegate)
|
||||
*ViewController:用于做button delegate
|
||||
*_rect:位置
|
||||
*_sel:方法
|
||||
*_Kind:1=setBackgroundImage 2= setImage
|
||||
*_index:tag
|
||||
*/
|
||||
+(UIButton*)InstanceButton:(NSString*)FileName Ect:(NSString*)ect FileName2:(NSString*)FileName2 Ect2:(NSString*)ect2 RECT:(CGRect)_rect RECT5:(CGRect)_rect5 AddView:(UIView*)view ViewController:(UIViewController*)VC SEL_:(SEL)_sel Kind:(int)_Kind TAG:(int)_index;
|
||||
/*
|
||||
*实例label
|
||||
*_info:lable信息
|
||||
*_rect:位置
|
||||
*name:字体名字,没有则,不需要特别设置
|
||||
*_red:字体红色
|
||||
*green:字体绿色
|
||||
*blue:字体蓝色
|
||||
*_fontsize:字体大小
|
||||
*target:parent类
|
||||
*Lines:几行
|
||||
*_index:tag
|
||||
*/
|
||||
+(UILabel*)InstanceLabel:(NSString*)_Info RECT:(CGRect)_rect RECT5:(CGRect)_rect5 FontName:(NSString*)Name Red:(CGFloat)_red green:(CGFloat)green blue:(CGFloat)blue FontSize:(int)_FontSize Target:(id)target Lines:(int)_lines TAG:(int)_index Ailgnment:(int)_ailgnment;
|
||||
|
||||
/*
|
||||
* 将指定控件移到当前最上层
|
||||
* _view:需要改变的view
|
||||
* _index:需要移动到最上层的索引
|
||||
*/
|
||||
+(void)MoveUIToTop:(UIView*)_view Index:(int)_index;
|
||||
/*
|
||||
* label:需要改变的label地址
|
||||
* name:字体名字
|
||||
* _red:红色值
|
||||
* green:绿色值
|
||||
* blue: 蓝色值
|
||||
* _fontsize:字体大小
|
||||
*/
|
||||
+(void)ChangeLable:(UILabel**)label FontName:(NSString*)Name Red:(CGFloat)_red green:(CGFloat)green blue:(CGFloat)blue FontSize:(int)_FontSize;
|
||||
|
||||
/*
|
||||
* 动画移位
|
||||
* _rect:需要移动到的位置
|
||||
* _view:需要移动的视图
|
||||
* _duration:动画时间
|
||||
* _str:动画名
|
||||
* sel:移动完成后返回的方法
|
||||
*/
|
||||
+(void)Translation:(CGRect)_rect Image:(UIView*)_view Duration:(float)_Duration Str:(NSString*)_str Select:(SEL)sel
|
||||
tager:(id)_tager;
|
||||
|
||||
/*
|
||||
*获得navigationarray的实例
|
||||
*/
|
||||
+(NSMutableArray*)NavigationArray;
|
||||
/*
|
||||
*通过name实例类,并添加navigation
|
||||
*Name:类名
|
||||
*_nav:保存navigation
|
||||
*_pvc:父类
|
||||
*/
|
||||
+(void)InstanceVC:(NSString*)Name ParentVC:(UIViewController*)_pVC;
|
||||
|
||||
+(void)TransitionView:(int)_index;
|
||||
//edit an.chen
|
||||
/*
|
||||
*移除动画
|
||||
*/
|
||||
+(void)RemoveWindowsAnimation;
|
||||
/*
|
||||
*增加push动画效果
|
||||
*ParentVC:父类vc
|
||||
*InsertVC:需要显示的vc
|
||||
*/
|
||||
+(void)PushAnimation:(UIViewController*)ParentVC InsertVC:(UIViewController*)InsertVC;
|
||||
|
||||
/*
|
||||
*增加push动画效果
|
||||
*ParentVC:父类vc
|
||||
*/
|
||||
+(void)PopAnimation:(UIViewController*)ParentVC;
|
||||
/*
|
||||
*增加pop动画效果 通过跳转的len
|
||||
*ParentVC:父类vc
|
||||
*/
|
||||
+(void)PopAnimation:(UIViewController*)ParentVC Len:(int)len;
|
||||
|
||||
/*
|
||||
*通过毫秒获得日期
|
||||
*/
|
||||
+(NSString*)StringTimeToDate:(NSString*)str;
|
||||
/*
|
||||
*通过毫秒获得日期
|
||||
*/
|
||||
+(NSDate*)StringTimeToRetrunDate:(NSString*)str;
|
||||
/*
|
||||
*转字符串 网络支持格式 转化为网络上可以传输的标准格式
|
||||
*/
|
||||
+ (NSString *) urlEncoderString:(NSString *)str;
|
||||
|
||||
/*
|
||||
dict: 字典文件
|
||||
key: 关键字
|
||||
kind: 种类 1:string 2:NSMutableArray 3:NSMutableDictionary
|
||||
*/
|
||||
+(id)tryObjectForKey:(NSMutableDictionary*)dict Key:(NSString*)key Kind:(int)kind;
|
||||
+(NSString*)ConvertFloat:(float)Num;
|
||||
+ (NSString *)setDivMarkup:(NSString *)markup;
|
||||
|
||||
/*
|
||||
* 实例通知
|
||||
* name: 闹钟显示名字
|
||||
* _action:是否动作
|
||||
* _date: 响铃日期
|
||||
*/
|
||||
+(void)InstanceLocalNotification:(NSString*)name HasAction:(BOOL)_Action Date:(NSDate*)date;
|
||||
/*
|
||||
* 计算二个星期索引相差多少天
|
||||
* oneWeekly:开始的星期索引
|
||||
* twoweekly:结束的星期索引
|
||||
*/
|
||||
+(int)TwoWeeklyDiffer:(int)oneWeekly TwoWeekly:(int)twoWeekly;
|
||||
/*
|
||||
*获得星期所代表的数字
|
||||
*/
|
||||
+(int)WeekInt:(NSString*)str;
|
||||
/*
|
||||
IOS7坐标移位
|
||||
*/
|
||||
+(int)IosPosChange;
|
||||
-(void)allok:(UIViewController *)controview;
|
||||
/*
|
||||
判断字符串是否为空
|
||||
*/
|
||||
+(NSString *)IsNull:(NSDictionary *)string Key:(NSString *)key;
|
||||
//将16进制html颜色转成 UIColor
|
||||
+ (UIColor *)getColorWithHexString:(NSString *)string;
|
||||
//判断是否是电子邮箱
|
||||
+ (BOOL)isEmail:(NSString*)email;
|
||||
//判断是否是手机号码
|
||||
+ (BOOL)isMobilePhone:(NSString *)mobilePhone;
|
||||
//判断是否是QQ号码
|
||||
+ (BOOL)isQQ:(NSString *)qq;
|
||||
//获得设备信息
|
||||
+ (NSMutableDictionary *)getDeviceInfo;
|
||||
|
||||
/*
|
||||
* 验证数据信息
|
||||
*type_ 1,phone number 2,email 3,normal
|
||||
*/
|
||||
+(BOOL)Validate:(NSString *)info type:(int)type_ infotitle:(NSString *)title viewController:(UIViewController *)controller;
|
||||
|
||||
//获得文件在沙盒中的路径,1:Document,2:Library\\Caches,3:App
|
||||
+ (NSString *)getFilePath:(NSString *)fileName PathType:(int)type;
|
||||
//返回字符串为文件名的前缀或后缀
|
||||
+ (NSString *)getStringItem:(NSString *)string WithType:(int)type;
|
||||
// 数据本地LoaclBookArray保存
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* str:需显示的信息 不重复
|
||||
*/
|
||||
+(void)ShowAlert:(NSString*)str title:(NSString *)title_ viewController:(UIViewController *)controller;
|
||||
#pragma mark - 生成当前时间字符串
|
||||
+ (NSString*)GetCurrentTimeString;
|
||||
#pragma mark - 生成文件路径
|
||||
+ (NSString*)GetPathByFileName:(NSString *)_fileName ofType:(NSString *)_type;
|
||||
+(int)ifauth;
|
||||
+( UIImage *)getImageWithFullScreenshot;
|
||||
+(UIImage*)imageByScalingAndCroppingForSize:(CGSize)targetSize image:(UIImage *)sourceImage;
|
||||
+(NSString *)danbian:(NSString *)str;
|
||||
//取得文件名
|
||||
+(NSString *)filename:(NSString *)file;
|
||||
+ (BOOL)isBlankString:(NSString *)string;
|
||||
@end
|
||||
1320
msext/Class/Common/FuncPublic.m
Executable file
1320
msext/Class/Common/FuncPublic.m
Executable file
File diff suppressed because it is too large
Load Diff
221
msext/Class/Common/GDataXML/GDataXMLNode.h
Executable file
221
msext/Class/Common/GDataXML/GDataXMLNode.h
Executable file
@@ -0,0 +1,221 @@
|
||||
/* Copyright (c) 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// These node, element, and document classes implement a subset of the methods
|
||||
// provided by NSXML. While NSXML behavior is mimicked as much as possible,
|
||||
// there are important differences.
|
||||
//
|
||||
// The biggest difference is that, since this is based on libxml2, there
|
||||
// is no retain model for the underlying node data. Rather than copy every
|
||||
// node obtained from a parse tree (which would have a substantial memory
|
||||
// impact), we rely on weak references, and it is up to the code that
|
||||
// created a document to retain it for as long as any
|
||||
// references rely on nodes inside that document tree.
|
||||
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
// libxml includes require that the target Header Search Paths contain
|
||||
//
|
||||
// /usr/include/libxml2
|
||||
//
|
||||
// and Other Linker Flags contain
|
||||
//
|
||||
// -lxml2
|
||||
|
||||
#import <libxml/tree.h>
|
||||
#import <libxml/parser.h>
|
||||
#import <libxml/xmlstring.h>
|
||||
#import <libxml/xpath.h>
|
||||
#import <libxml/xpathInternals.h>
|
||||
|
||||
|
||||
#ifdef GDATA_TARGET_NAMESPACE
|
||||
// we're using target namespace macros
|
||||
#import "GDataDefines.h"
|
||||
#endif
|
||||
|
||||
#undef _EXTERN
|
||||
#undef _INITIALIZE_AS
|
||||
#ifdef GDATAXMLNODE_DEFINE_GLOBALS
|
||||
#define _EXTERN
|
||||
#define _INITIALIZE_AS(x) =x
|
||||
#else
|
||||
#if defined(__cplusplus)
|
||||
#define _EXTERN extern "C"
|
||||
#else
|
||||
#define _EXTERN extern
|
||||
#endif
|
||||
#define _INITIALIZE_AS(x)
|
||||
#endif
|
||||
|
||||
// when no namespace dictionary is supplied for XPath, the default namespace
|
||||
// for the evaluated tree is registered with the prefix _def_ns
|
||||
_EXTERN const char* kGDataXMLXPathDefaultNamespacePrefix _INITIALIZE_AS("_def_ns");
|
||||
|
||||
// Nomenclature for method names:
|
||||
//
|
||||
// Node = GData node
|
||||
// XMLNode = xmlNodePtr
|
||||
//
|
||||
// So, for example:
|
||||
// + (id)nodeConsumingXMLNode:(xmlNodePtr)theXMLNode;
|
||||
|
||||
@class NSArray, NSDictionary, NSError, NSString, NSURL;
|
||||
@class GDataXMLElement, GDataXMLDocument;
|
||||
|
||||
enum {
|
||||
GDataXMLInvalidKind = 0,
|
||||
GDataXMLDocumentKind,
|
||||
GDataXMLElementKind,
|
||||
GDataXMLAttributeKind,
|
||||
GDataXMLNamespaceKind,
|
||||
GDataXMLProcessingInstructionKind,
|
||||
GDataXMLCommentKind,
|
||||
GDataXMLTextKind,
|
||||
GDataXMLDTDKind,
|
||||
GDataXMLEntityDeclarationKind,
|
||||
GDataXMLAttributeDeclarationKind,
|
||||
GDataXMLElementDeclarationKind,
|
||||
GDataXMLNotationDeclarationKind
|
||||
};
|
||||
|
||||
typedef NSUInteger GDataXMLNodeKind;
|
||||
|
||||
@interface GDataXMLNode : NSObject <NSCopying> {
|
||||
@protected
|
||||
// NSXMLNodes can have a namespace URI or prefix even if not part
|
||||
// of a tree; xmlNodes cannot. When we create nodes apart from
|
||||
// a tree, we'll store the dangling prefix or URI in the xmlNode's name,
|
||||
// like
|
||||
// "prefix:name"
|
||||
// or
|
||||
// "{http://uri}:name"
|
||||
//
|
||||
// We will fix up the node's namespace and name (and those of any children)
|
||||
// later when adding the node to a tree with addChild: or addAttribute:.
|
||||
// See fixUpNamespacesForNode:.
|
||||
|
||||
xmlNodePtr xmlNode_; // may also be an xmlAttrPtr or xmlNsPtr
|
||||
BOOL shouldFreeXMLNode_; // if yes, xmlNode_ will be free'd in dealloc
|
||||
|
||||
// cached values
|
||||
NSString *cachedName_;
|
||||
NSArray *cachedChildren_;
|
||||
NSArray *cachedAttributes_;
|
||||
}
|
||||
|
||||
+ (GDataXMLElement *)elementWithName:(NSString *)name;
|
||||
+ (GDataXMLElement *)elementWithName:(NSString *)name stringValue:(NSString *)value;
|
||||
+ (GDataXMLElement *)elementWithName:(NSString *)name URI:(NSString *)value;
|
||||
|
||||
+ (id)attributeWithName:(NSString *)name stringValue:(NSString *)value;
|
||||
+ (id)attributeWithName:(NSString *)name URI:(NSString *)attributeURI stringValue:(NSString *)value;
|
||||
|
||||
+ (id)namespaceWithName:(NSString *)name stringValue:(NSString *)value;
|
||||
|
||||
+ (id)textWithStringValue:(NSString *)value;
|
||||
|
||||
- (NSString *)stringValue;
|
||||
- (void)setStringValue:(NSString *)str;
|
||||
|
||||
- (NSUInteger)childCount;
|
||||
- (NSArray *)children;
|
||||
- (GDataXMLNode *)childAtIndex:(unsigned)index;
|
||||
|
||||
- (NSString *)localName;
|
||||
- (NSString *)name;
|
||||
- (NSString *)prefix;
|
||||
- (NSString *)URI;
|
||||
|
||||
- (GDataXMLNodeKind)kind;
|
||||
|
||||
- (NSString *)XMLString;
|
||||
|
||||
+ (NSString *)localNameForName:(NSString *)name;
|
||||
+ (NSString *)prefixForName:(NSString *)name;
|
||||
|
||||
// This is the preferred entry point for nodesForXPath. This takes an explicit
|
||||
// namespace dictionary (keys are prefixes, values are URIs).
|
||||
- (NSArray *)nodesForXPath:(NSString *)xpath namespaces:(NSDictionary *)namespaces error:(NSError **)error;
|
||||
|
||||
// This implementation of nodesForXPath registers namespaces only from the
|
||||
// document's root node. _def_ns may be used as a prefix for the default
|
||||
// namespace, though there's no guarantee that the default namespace will
|
||||
// be consistenly the same namespace in server responses.
|
||||
- (NSArray *)nodesForXPath:(NSString *)xpath error:(NSError **)error;
|
||||
|
||||
// access to the underlying libxml node; be sure to release the cached values
|
||||
// if you change the underlying tree at all
|
||||
- (xmlNodePtr)XMLNode;
|
||||
- (void)releaseCachedValues;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface GDataXMLElement : GDataXMLNode
|
||||
|
||||
- (id)initWithXMLString:(NSString *)str error:(NSError **)error;
|
||||
|
||||
- (NSArray *)namespaces;
|
||||
- (void)setNamespaces:(NSArray *)namespaces;
|
||||
- (void)addNamespace:(GDataXMLNode *)aNamespace;
|
||||
|
||||
// addChild adds a copy of the child node to the element
|
||||
- (void)addChild:(GDataXMLNode *)child;
|
||||
- (void)removeChild:(GDataXMLNode *)child;
|
||||
|
||||
- (NSArray *)elementsForName:(NSString *)name;
|
||||
- (NSArray *)elementsForLocalName:(NSString *)localName URI:(NSString *)URI;
|
||||
|
||||
- (NSArray *)attributes;
|
||||
- (GDataXMLNode *)attributeForName:(NSString *)name;
|
||||
- (GDataXMLNode *)attributeForLocalName:(NSString *)name URI:(NSString *)attributeURI;
|
||||
- (void)addAttribute:(GDataXMLNode *)attribute;
|
||||
|
||||
- (NSString *)resolvePrefixForNamespaceURI:(NSString *)namespaceURI;
|
||||
|
||||
@end
|
||||
|
||||
@interface GDataXMLDocument : NSObject {
|
||||
@protected
|
||||
xmlDoc* xmlDoc_; // strong; always free'd in dealloc
|
||||
}
|
||||
|
||||
- (id)initWithXMLString:(NSString *)str options:(unsigned int)mask error:(NSError **)error;
|
||||
- (id)initWithData:(NSData *)data options:(unsigned int)mask error:(NSError **)error;
|
||||
|
||||
// initWithRootElement uses a copy of the argument as the new document's root
|
||||
- (id)initWithRootElement:(GDataXMLElement *)element;
|
||||
|
||||
- (GDataXMLElement *)rootElement;
|
||||
|
||||
- (NSData *)XMLData;
|
||||
|
||||
- (void)setVersion:(NSString *)version;
|
||||
- (void)setCharacterEncoding:(NSString *)encoding;
|
||||
|
||||
// This is the preferred entry point for nodesForXPath. This takes an explicit
|
||||
// namespace dictionary (keys are prefixes, values are URIs).
|
||||
- (NSArray *)nodesForXPath:(NSString *)xpath namespaces:(NSDictionary *)namespaces error:(NSError **)error;
|
||||
|
||||
// This implementation of nodesForXPath registers namespaces only from the
|
||||
// document's root node. _def_ns may be used as a prefix for the default
|
||||
// namespace, though there's no guarantee that the default namespace will
|
||||
// be consistenly the same namespace in server responses.
|
||||
- (NSArray *)nodesForXPath:(NSString *)xpath error:(NSError **)error;
|
||||
|
||||
- (NSString *)description;
|
||||
@end
|
||||
1830
msext/Class/Common/GDataXML/GDataXMLNode.m
Executable file
1830
msext/Class/Common/GDataXML/GDataXMLNode.m
Executable file
File diff suppressed because it is too large
Load Diff
23
msext/Class/Common/NavgationController.h
Executable file
23
msext/Class/Common/NavgationController.h
Executable file
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// NavgationController.h
|
||||
// TestNav
|
||||
//
|
||||
// Created by iTrends on 13-4-18.
|
||||
// Copyright (c) 2013年 iTrends. All rights reserved.
|
||||
//
|
||||
|
||||
typedef enum {
|
||||
NavgationTypeMaskPortrait=1,/*竖屏*/
|
||||
|
||||
NavgationTypeMaskLandscape,/*横屏*/
|
||||
|
||||
NavgationTypeMaskAll,/*横竖屏*/
|
||||
|
||||
}NavgationType;
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
@interface NavgationController : UINavigationController
|
||||
@property(nonatomic,assign)NavgationType navType;
|
||||
-(id)initWithRootViewController:(UIViewController *)rootViewController Navtype:(NavgationType)navType;
|
||||
|
||||
@end
|
||||
118
msext/Class/Common/NavgationController.m
Executable file
118
msext/Class/Common/NavgationController.m
Executable file
@@ -0,0 +1,118 @@
|
||||
//
|
||||
// NavgationController.m
|
||||
// TestNav
|
||||
//
|
||||
// Created by iTrends on 13-4-18.
|
||||
// Copyright (c) 2013年 iTrends. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NavgationController.h"
|
||||
#import "AppDelegate.h"
|
||||
#import "threeView.h"
|
||||
@interface NavgationController ()
|
||||
|
||||
@end
|
||||
|
||||
@implementation NavgationController
|
||||
|
||||
@synthesize navType=_navType;
|
||||
|
||||
-(id)initWithRootViewController:(UIViewController *)rootViewController Navtype:(NavgationType)navType
|
||||
{
|
||||
if(self){
|
||||
self.navType=navType;
|
||||
self=[super initWithRootViewController:rootViewController];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//- (NSUInteger)supportedInterfaceOrientations NS_AVAILABLE_IOS(6_0){
|
||||
// // if ([[FuncPublic GetDefaultInfo:@"stateOrie"] isEqualToString:@"yes"]) {
|
||||
// switch (self.navType) {
|
||||
// case NavgationTypeMaskPortrait:
|
||||
// return UIInterfaceOrientationMaskPortrait|UIInterfaceOrientationMaskPortraitUpsideDown;
|
||||
// break;
|
||||
// case NavgationTypeMaskLandscape:
|
||||
// return UIInterfaceOrientationMaskLandscape;
|
||||
// break;
|
||||
// case NavgationTypeMaskAll:
|
||||
// return UIInterfaceOrientationMaskAll;
|
||||
// break;
|
||||
// default:
|
||||
// break;
|
||||
// }
|
||||
// }else
|
||||
// {
|
||||
// AppDelegate *delegate=[UIApplication sharedApplication].delegate;
|
||||
// return delegate.oriention;
|
||||
// }
|
||||
//}
|
||||
//- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
|
||||
//
|
||||
// //return UIInterfaceOrientationLandscapeLeft;
|
||||
// switch (self.navType) {
|
||||
// case NavgationTypeMaskPortrait:
|
||||
// return UIInterfaceOrientationPortrait;
|
||||
// break;
|
||||
// case NavgationTypeMaskLandscape:
|
||||
// return UIInterfaceOrientationLandscapeLeft;
|
||||
// break;
|
||||
// case NavgationTypeMaskAll:
|
||||
// return UIInterfaceOrientationLandscapeLeft|UIInterfaceOrientationPortrait;
|
||||
// break;
|
||||
// default:
|
||||
// break;
|
||||
// }
|
||||
//
|
||||
//}
|
||||
//支持的方向 因为界面A我们只需要支持竖屏
|
||||
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
|
||||
|
||||
return [self.viewControllers.firstObject supportedInterfaceOrientations];
|
||||
}
|
||||
-(BOOL)shouldAutorotate{
|
||||
|
||||
if ([FuncPublic SharedFuncPublic]._CurrentShow==3) {
|
||||
return NO;
|
||||
}
|
||||
return self.viewControllers.firstObject.shouldAutorotate;
|
||||
|
||||
}
|
||||
|
||||
|
||||
//当前viewcontroller默认的屏幕方向 - 横屏显示
|
||||
|
||||
//-(UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
|
||||
//
|
||||
// return UIInterfaceOrientationLandscapeRight;
|
||||
//
|
||||
//}
|
||||
|
||||
/*
|
||||
若ios得版本号小于6.0
|
||||
在nav->rootviewcontroller中加入如下代码
|
||||
self替换为xxx.navigationcontroller
|
||||
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation NS_DEPRECATED_IOS(2_0, 6_0){
|
||||
|
||||
switch (self.navType) {
|
||||
case NavgationTypeMaskPortrait:
|
||||
return UIInterfaceOrientationIsPortrait(toInterfaceOrientation);
|
||||
break;
|
||||
case NavgationTypeMaskLandscape:
|
||||
return UIInterfaceOrientationIsPortrait(toInterfaceOrientation);
|
||||
break;
|
||||
case NavgationTypeMaskAll:
|
||||
return YES;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
}*/
|
||||
|
||||
|
||||
@end
|
||||
112
msext/Class/Common/SGDefineInfo.h
Executable file
112
msext/Class/Common/SGDefineInfo.h
Executable file
@@ -0,0 +1,112 @@
|
||||
//
|
||||
// SGDefineInfo.h
|
||||
// SGFramework
|
||||
//
|
||||
// Created by an chen on 12-9-17.
|
||||
// Copyright 2012年 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
/*
|
||||
* 释放
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#define SG_RELEASE(x)\
|
||||
if(x!=nil)\
|
||||
{\
|
||||
[x release];\
|
||||
x = nil;\
|
||||
}
|
||||
#define IS_IPHONE_5 ( fabs( ( double )[ [ UIScreen mainScreen ] bounds ].size.height - ( double )568 ) < DBL_EPSILON )
|
||||
#define GATEWAY_DELAYER 20
|
||||
/*
|
||||
if(x!=nil)\
|
||||
{\
|
||||
if( [x retainCount] > 0 )\
|
||||
{\
|
||||
[x release];\
|
||||
x = nil;\
|
||||
}\
|
||||
}
|
||||
*/
|
||||
//
|
||||
// CGRect rect = [title.text boundingRectWithSize:CGSizeMake(title.frame.size.width, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading attributes:@{NSFontAttributeName: title.font} context:nil];
|
||||
//
|
||||
|
||||
/**/
|
||||
/*
|
||||
* 转换str
|
||||
*/
|
||||
#define DATA(X) [X dataUsingEncoding:NSUTF8StringEncoding]
|
||||
#define DocumentsPath [NSHomeDirectory() stringByAppendingString:@"/Docunents/"]
|
||||
#define IS_IPHONE_7 [[[UIDevice currentDevice] systemVersion] floatValue] >= 7
|
||||
#define IS_IPHONE_6 [[[UIDevice currentDevice] systemVersion] floatValue] >= 6
|
||||
#define IOS_VERSION [[[UIDevice currentDevice] systemVersion] floatValue]
|
||||
#define IOS_20 20
|
||||
#define UpOrientation [[UIApplication sharedApplication] statusBarOrientation] == UIDeviceOrientationPortrait || [[UIApplication sharedApplication] statusBarOrientation] == UIDeviceOrientationPortraitUpsideDown
|
||||
#define LandOrientation [[UIApplication sharedApplication] statusBarOrientation]==UIDeviceOrientationLandscapeLeft || [[UIApplication sharedApplication] statusBarOrientation] == UIDeviceOrientationLandscapeRight
|
||||
#define RGBACOLOR(r,g,b,a) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:(a)]
|
||||
//edit an.chen
|
||||
#define SERVER @"http://niuniuapi.0791ts.cn/"
|
||||
#define SERVERNew @"http://ylyxservice3.0791ts.cn/config/"
|
||||
#define SERVERtest @"https://www.tsysjw.com/niuniu/updata_json.txt"
|
||||
#define SERVERShop @"http://ylyx.0791ts.cn/version_shop.json"
|
||||
|
||||
#define SERVERNewtest @"http://ylyxservice2.0791ts.cn/config/"
|
||||
#define SERVERNewtwo @"http://ylyx.0791ts.cn/version_shop.json"
|
||||
|
||||
#define appstore @"0" // 1 appstore 0 企业签
|
||||
//#define SERVER @"http://117.21.209.145:8080/" //http://geezer.wicp.net:46877/ http://117.21.210.12/ http://aqxtest.appletrees.com.cn/ //http://cc.tshuixin.com.cn/pay/ http://m.jxpph.com/json/
|
||||
//http://geezer.wicp.net:46877/ http://117.21.210.12/ http://geezer.wicp.net:56221/ http://117.21.209.145:8080/
|
||||
#define SERVERTwo @"http://bookstore.eobook.com/post/"
|
||||
#define SERVERSUB @"http://ylyxservice2.0791ts.cn"
|
||||
#define RGB(r,g,b) [UIColor colorWithRed:(r)/255.0f green:(g)/255.0f blue:(b)/255.0f alpha:1]
|
||||
#ifdef DEBUG
|
||||
|
||||
# define DLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
|
||||
|
||||
#else
|
||||
|
||||
# define DLog(...)
|
||||
|
||||
#endif
|
||||
|
||||
#define DocumentsPath [NSHomeDirectory() stringByAppendingString:@"/Docunents/"]
|
||||
//-fno-objc-arc 关闭arc
|
||||
/*
|
||||
chao
|
||||
*/
|
||||
#define DEVW [[UIScreen mainScreen] bounds].size.width
|
||||
#define DEVH [[UIScreen mainScreen] bounds].size.height
|
||||
#define VDEVW self.view.frame.size.width
|
||||
#define VDEVH self.view.frame.size.height
|
||||
#define NavBarBackImage 1000
|
||||
#define NavBarSubviews 2000
|
||||
#define EndCellTag 5000
|
||||
#define DownVCBT 7000
|
||||
#define RootItemBT 3000
|
||||
#define OrderTag 4000
|
||||
#define PublicTag 10000//public tag
|
||||
#define PublicTagTwo 20000000//publictwo tag
|
||||
#define PublicTagThree 30000//
|
||||
#define PublicTagfour 40000//
|
||||
#define PublicTagfive 50000//
|
||||
#define PublicTagsix 60000//
|
||||
#define PublicTagseven 70000//
|
||||
#define PublicTageight 80000//
|
||||
#define Max_ZView 99999
|
||||
|
||||
#define iosversion 1
|
||||
#define gameversion 1
|
||||
|
||||
#define gamehallname @"开元棋牌"
|
||||
static NSString *kAuthScope = @"snsapi_message,snsapi_userinfo,snsapi_friend,snsapi_contact";
|
||||
static NSString *kAuthOpenID = @"wxa5fcff77c40d721c";
|
||||
static NSString *kAuthState = @"wechat_sdk";
|
||||
static NSString *Appsecret = @"489fc47bee2f0d61814f71a8634a9380";
|
||||
static NSString *kMessageAction = @"<action>dotalist</action>";
|
||||
#define webPathtcp [[NSBundle mainBundle] pathForResource:@"web" ofType:nil]
|
||||
/*
|
||||
chao
|
||||
*/
|
||||
71
msext/Class/Common/Unzip/.svn/all-wcprops
Executable file
71
msext/Class/Common/Unzip/.svn/all-wcprops
Executable file
@@ -0,0 +1,71 @@
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 87
|
||||
/svn/com.mouee.ios/!svn/ver/133/release/trunk/MoueeIOS/Release/Release/ThirdParty/Unzip
|
||||
END
|
||||
ioapi.c
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 95
|
||||
/svn/com.mouee.ios/!svn/ver/133/release/trunk/MoueeIOS/Release/Release/ThirdParty/Unzip/ioapi.c
|
||||
END
|
||||
zip.c
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 93
|
||||
/svn/com.mouee.ios/!svn/ver/133/release/trunk/MoueeIOS/Release/Release/ThirdParty/Unzip/zip.c
|
||||
END
|
||||
unzip.c
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 95
|
||||
/svn/com.mouee.ios/!svn/ver/133/release/trunk/MoueeIOS/Release/Release/ThirdParty/Unzip/unzip.c
|
||||
END
|
||||
crypt.h
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 95
|
||||
/svn/com.mouee.ios/!svn/ver/133/release/trunk/MoueeIOS/Release/Release/ThirdParty/Unzip/crypt.h
|
||||
END
|
||||
ioapi.h
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 95
|
||||
/svn/com.mouee.ios/!svn/ver/133/release/trunk/MoueeIOS/Release/Release/ThirdParty/Unzip/ioapi.h
|
||||
END
|
||||
mztools.c
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 97
|
||||
/svn/com.mouee.ios/!svn/ver/133/release/trunk/MoueeIOS/Release/Release/ThirdParty/Unzip/mztools.c
|
||||
END
|
||||
zip.h
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 93
|
||||
/svn/com.mouee.ios/!svn/ver/133/release/trunk/MoueeIOS/Release/Release/ThirdParty/Unzip/zip.h
|
||||
END
|
||||
ZipArchive.h
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 100
|
||||
/svn/com.mouee.ios/!svn/ver/133/release/trunk/MoueeIOS/Release/Release/ThirdParty/Unzip/ZipArchive.h
|
||||
END
|
||||
unzip.h
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 95
|
||||
/svn/com.mouee.ios/!svn/ver/133/release/trunk/MoueeIOS/Release/Release/ThirdParty/Unzip/unzip.h
|
||||
END
|
||||
ZipArchive.mm
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 101
|
||||
/svn/com.mouee.ios/!svn/ver/133/release/trunk/MoueeIOS/Release/Release/ThirdParty/Unzip/ZipArchive.mm
|
||||
END
|
||||
mztools.h
|
||||
K 25
|
||||
svn:wc:ra_dav:version-url
|
||||
V 97
|
||||
/svn/com.mouee.ios/!svn/ver/133/release/trunk/MoueeIOS/Release/Release/ThirdParty/Unzip/mztools.h
|
||||
END
|
||||
402
msext/Class/Common/Unzip/.svn/entries
Executable file
402
msext/Class/Common/Unzip/.svn/entries
Executable file
@@ -0,0 +1,402 @@
|
||||
10
|
||||
|
||||
dir
|
||||
158
|
||||
https://192.168.1.108/svn/com.mouee.ios/release/trunk/MoueeIOS/Release/Release/ThirdParty/Unzip
|
||||
https://192.168.1.108/svn/com.mouee.ios
|
||||
|
||||
|
||||
|
||||
2012-08-25T07:41:16.910000Z
|
||||
133
|
||||
liwei
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
edcb6c81-38c0-4a4f-bab3-e02b3f82dc25
|
||||
|
||||
ioapi.c
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2012-05-24T05:43:20.000000Z
|
||||
8adffe86593395acffcf20b2589aed9d
|
||||
2012-08-25T07:41:16.910000Z
|
||||
133
|
||||
liwei
|
||||
has-props
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
3871
|
||||
|
||||
zip.c
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2012-05-24T05:43:20.000000Z
|
||||
29dfe9610a5057bfd48019b81c8f62ec
|
||||
2012-08-25T07:41:16.910000Z
|
||||
133
|
||||
liwei
|
||||
has-props
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
38682
|
||||
|
||||
unzip.c
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2012-05-24T05:43:20.000000Z
|
||||
64cd688b57801432f305151e1fa85341
|
||||
2012-08-25T07:41:16.910000Z
|
||||
133
|
||||
liwei
|
||||
has-props
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
50980
|
||||
|
||||
crypt.h
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2012-05-24T05:43:20.000000Z
|
||||
6b19101600a00dad85360d4d19f240aa
|
||||
2012-08-25T07:41:16.910000Z
|
||||
133
|
||||
liwei
|
||||
has-props
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
4844
|
||||
|
||||
ioapi.h
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2012-05-24T05:43:20.000000Z
|
||||
b86ae4b3a0d459c8b232aae47c9869ac
|
||||
2012-08-25T07:41:16.910000Z
|
||||
133
|
||||
liwei
|
||||
has-props
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
2610
|
||||
|
||||
mztools.c
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2012-05-24T05:43:20.000000Z
|
||||
5f35a4fc54a5b19a1ade4f0133b45a0f
|
||||
2012-08-25T07:41:16.910000Z
|
||||
133
|
||||
liwei
|
||||
has-props
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
8266
|
||||
|
||||
zip.h
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2012-05-24T05:43:20.000000Z
|
||||
b6357a4b8ff836ea4e7098bedc2f3d35
|
||||
2012-08-25T07:41:16.910000Z
|
||||
133
|
||||
liwei
|
||||
has-props
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
9082
|
||||
|
||||
ZipArchive.h
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2012-05-24T05:43:20.000000Z
|
||||
6d54af2266e311c8afd1f8c363c63ac3
|
||||
2012-08-25T07:41:16.910000Z
|
||||
133
|
||||
liwei
|
||||
has-props
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
1095
|
||||
|
||||
unzip.h
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2012-05-24T05:43:20.000000Z
|
||||
f8dbf52fff414afddc5af0af36c5dc25
|
||||
2012-08-25T07:41:16.910000Z
|
||||
133
|
||||
liwei
|
||||
has-props
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
13322
|
||||
|
||||
ZipArchive.mm
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2012-05-24T05:43:20.000000Z
|
||||
c9beebe769f56e2b81d21952f4e40360
|
||||
2012-08-25T07:41:16.910000Z
|
||||
133
|
||||
liwei
|
||||
has-props
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
8851
|
||||
|
||||
mztools.h
|
||||
file
|
||||
|
||||
|
||||
|
||||
|
||||
2012-05-24T05:43:20.000000Z
|
||||
bdf8dbff157a17e3e64df50cbd0e691f
|
||||
2012-08-25T07:41:16.910000Z
|
||||
133
|
||||
liwei
|
||||
has-props
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
712
|
||||
|
||||
5
msext/Class/Common/Unzip/.svn/prop-base/ZipArchive.h.svn-base
Executable file
5
msext/Class/Common/Unzip/.svn/prop-base/ZipArchive.h.svn-base
Executable file
@@ -0,0 +1,5 @@
|
||||
K 14
|
||||
svn:executable
|
||||
V 1
|
||||
*
|
||||
END
|
||||
5
msext/Class/Common/Unzip/.svn/prop-base/ZipArchive.mm.svn-base
Executable file
5
msext/Class/Common/Unzip/.svn/prop-base/ZipArchive.mm.svn-base
Executable file
@@ -0,0 +1,5 @@
|
||||
K 14
|
||||
svn:executable
|
||||
V 1
|
||||
*
|
||||
END
|
||||
5
msext/Class/Common/Unzip/.svn/prop-base/crypt.h.svn-base
Executable file
5
msext/Class/Common/Unzip/.svn/prop-base/crypt.h.svn-base
Executable file
@@ -0,0 +1,5 @@
|
||||
K 14
|
||||
svn:executable
|
||||
V 1
|
||||
*
|
||||
END
|
||||
5
msext/Class/Common/Unzip/.svn/prop-base/ioapi.c.svn-base
Executable file
5
msext/Class/Common/Unzip/.svn/prop-base/ioapi.c.svn-base
Executable file
@@ -0,0 +1,5 @@
|
||||
K 14
|
||||
svn:executable
|
||||
V 1
|
||||
*
|
||||
END
|
||||
5
msext/Class/Common/Unzip/.svn/prop-base/ioapi.h.svn-base
Executable file
5
msext/Class/Common/Unzip/.svn/prop-base/ioapi.h.svn-base
Executable file
@@ -0,0 +1,5 @@
|
||||
K 14
|
||||
svn:executable
|
||||
V 1
|
||||
*
|
||||
END
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user