diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 diff --git a/AFNetworking/AFHTTPClient.h b/AFNetworking/AFHTTPClient.h new file mode 100644 index 0000000..cdc1666 --- /dev/null +++ b/AFNetworking/AFHTTPClient.h @@ -0,0 +1,516 @@ +// AFHTTPClient.h +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import + +@class AFHTTPRequestOperation; +@protocol AFHTTPClientOperation; +@protocol AFMultipartFormData; + +/** + Posted when network reachability changes. + The notification object is an `NSNumber` object containing the boolean value for the current network reachability. + This notification contains no information in the `userInfo` dictionary. + + @warning In order for network reachability to be monitored, include the `SystemConfiguration` framework in the active target's "Link Binary With Library" build phase, and add `#import ` to the header prefix of the project (Prefix.pch). + */ +#ifdef _SYSTEMCONFIGURATION_H +extern NSString * const AFNetworkingReachabilityDidChangeNotification; +#endif + +/** + Specifies network reachability of the client to its `baseURL` domain. + */ +#ifdef _SYSTEMCONFIGURATION_H +typedef enum { + AFNetworkReachabilityStatusUnknown = -1, + AFNetworkReachabilityStatusNotReachable = 0, + AFNetworkReachabilityStatusReachableViaWWAN = 1, + AFNetworkReachabilityStatusReachableViaWiFi = 2, +} AFNetworkReachabilityStatus; +#endif + +/** + Specifies the method used to encode parameters into request body. + */ +typedef enum { + AFFormURLParameterEncoding, + AFJSONParameterEncoding, + AFPropertyListParameterEncoding, +} AFHTTPClientParameterEncoding; + +/** + Returns a string, replacing certain characters with the equivalent percent escape sequence based on the specified encoding. + + @param string The string to URL encode + @param encoding The encoding to use for the replacement. If you are uncertain of the correct encoding, you should use UTF-8 (NSUTF8StringEncoding), which is the encoding designated by RFC 3986 as the correct encoding for use in URLs. + + @discussion The characters escaped are all characters that are not legal URL characters (based on RFC 3986), including any whitespace, punctuation, or special characters. + + @return A URL-encoded string. If it does not need to be modified (no percent escape sequences are missing), this function may merely return string argument. + */ +extern NSString * AFURLEncodedStringFromStringWithEncoding(NSString *string, NSStringEncoding encoding); + +/** + Returns a query string constructed by a set of parameters, using the specified encoding. + + @param parameters The parameters used to construct the query string + @param encoding The encoding to use in constructing the query string. If you are uncertain of the correct encoding, you should use UTF-8 (NSUTF8StringEncoding), which is the encoding designated by RFC 3986 as the correct encoding for use in URLs. + + @discussion Query strings are constructed by collecting each key-value pair, URL-encoding a string representation of the key-value pair, and then joining the components with "&". + + + If a key-value pair has a an `NSArray` for its value, each member of the array will be represented in the format `key[]=value1&key[]value2`. Otherwise, the key-value pair will be formatted as "key=value". String representations of both keys and values are derived using the `-description` method. The constructed query string does not include the ? character used to delimit the query component. + + @return A URL-encoded query string + */ +extern NSString * AFQueryStringFromParametersWithEncoding(NSDictionary *parameters, NSStringEncoding encoding); + +/** + `AFHTTPClient` captures the common patterns of communicating with an web application over HTTP. It encapsulates information like base URL, authorization credentials, and HTTP headers, and uses them to construct and manage the execution of HTTP request operations. + + ## Automatic Content Parsing + + Instances of `AFHTTPClient` may specify which types of requests it expects and should handle by registering HTTP operation classes for automatic parsing. Registered classes will determine whether they can handle a particular request, and then construct a request operation accordingly in `enqueueHTTPRequestOperationWithRequest:success:failure`. See `AFHTTPClientOperation` for further details. + + ## Subclassing Notes + + In most cases, one should create an `AFHTTPClient` subclass for each website or web application that your application communicates with. It is often useful, also, to define a class method that returns a singleton shared HTTP client in each subclass, that persists authentication credentials and other configuration across the entire application. + + ## Methods to Override + + To change the behavior of all url request construction for an `AFHTTPClient` subclass, override `requestWithMethod:path:parameters`. + + To change the behavior of all request operation construction for an `AFHTTPClient` subclass, override `enqueueHTTPRequestOperationWithRequest:success:failure`. + + ## Default Headers + + By default, `AFHTTPClient` sets the following HTTP headers: + + - `Accept-Encoding: gzip` + - `Accept-Language: ([NSLocale preferredLanguages]), en-us;q=0.8` + - `User-Agent: (generated user agent)` + + You can override these HTTP headers or define new ones using `setDefaultHeader:value:`. + + ## URL Construction Using Relative Paths + + Both `requestWithMethod:path:parameters` and `multipartFormRequestWithMethod:path:parameters:constructingBodyWithBlock:` construct URLs from the path relative to the `baseURL`, using `NSURL +URLWithString:relativeToURL:`. Below are a few examples of how `baseURL` and relative paths interract: + + NSURL *baseURL = [NSURL URLWithString:@"http://example.com/v1/"]; + [NSURL URLWithString:@"foo" relativeToURL:baseURL]; // http://example.com/v1/foo + [NSURL URLWithString:@"foo?bar=baz" relativeToURL:baseURL]; // http://example.com/v1/foo?bar=baz + [NSURL URLWithString:@"/foo" relativeToURL:baseURL]; // http://example.com/foo + [NSURL URLWithString:@"foo/" relativeToURL:baseURL]; // http://example.com/v1/foo + [NSURL URLWithString:@"/foo/" relativeToURL:baseURL]; // http://example.com/foo/ + [NSURL URLWithString:@"http://example2.com/" relativeToURL:baseURL]; // http://example2.com/ + + */ +@interface AFHTTPClient : NSObject + +///--------------------------------------- +/// @name Accessing HTTP Client Properties +///--------------------------------------- + +/** + The url used as the base for paths specified in methods such as `getPath:parameteres:success:failure` + */ +@property (readonly, nonatomic, retain) NSURL *baseURL; + +/** + The string encoding used in constructing url requests. This is `NSUTF8StringEncoding` by default. + */ +@property (nonatomic, assign) NSStringEncoding stringEncoding; + +/** + The `AFHTTPClientParameterEncoding` value corresponding to how parameters are encoded into a request body. This is `AFFormURLParameterEncoding` by default. + + @warning JSON encoding will automatically use JSONKit, SBJSON, YAJL, or NextiveJSON, if provided. Otherwise, the built-in `NSJSONSerialization` class is used, if available (iOS 5.0 and Mac OS 10.7). If the build target does not either support `NSJSONSerialization` or include a third-party JSON library, a runtime exception will be thrown when attempting to encode parameters as JSON. + */ +@property (nonatomic, assign) AFHTTPClientParameterEncoding parameterEncoding; + +/** + The operation queue which manages operations enqueued by the HTTP client. + */ +@property (readonly, nonatomic, retain) NSOperationQueue *operationQueue; + +/** + The reachability status from the device to the current `baseURL` of the `AFHTTPClient`. + + @warning This property requires the `SystemConfiguration` framework. Add it in the active target's "Link Binary With Library" build phase, and add `#import ` to the header prefix of the project (Prefix.pch). + */ +#ifdef _SYSTEMCONFIGURATION_H +@property (readonly, nonatomic, assign) AFNetworkReachabilityStatus networkReachabilityStatus; +#endif + +///--------------------------------------------- +/// @name Creating and Initializing HTTP Clients +///--------------------------------------------- + +/** + Creates and initializes an `AFHTTPClient` object with the specified base URL. + + @param url The base URL for the HTTP client. This argument must not be nil. + + @return The newly-initialized HTTP client + */ ++ (AFHTTPClient *)clientWithBaseURL:(NSURL *)url; + +/** + Initializes an `AFHTTPClient` object with the specified base URL. + + @param url The base URL for the HTTP client. This argument must not be nil. + + @discussion This is the designated initializer. + + @return The newly-initialized HTTP client + */ +- (id)initWithBaseURL:(NSURL *)url; + +///----------------------------------- +/// @name Managing Reachability Status +///----------------------------------- + +/** + Sets a callback to be executed when the network availability of the `baseURL` host changes. + + @param block A block object to be executed when the network availability of the `baseURL` host changes.. This block has no return value and takes a single argument which represents the various reachability states from the device to the `baseURL`. + + @warning This method requires the `SystemConfiguration` framework. Add it in the active target's "Link Binary With Library" build phase, and add `#import ` to the header prefix of the project (Prefix.pch). + */ +#ifdef _SYSTEMCONFIGURATION_H +- (void)setReachabilityStatusChangeBlock:(void (^)(AFNetworkReachabilityStatus status))block; +#endif + +///------------------------------- +/// @name Managing HTTP Operations +///------------------------------- + +/** + Attempts to register a subclass of `AFHTTPRequestOperation`, adding it to a chain to automatically generate request operations from a URL request. + + @param The subclass of `AFHTTPRequestOperation` to register + + @return `YES` if the registration is successful, `NO` otherwise. The only failure condition is if `operationClass` does is not a subclass of `AFHTTPRequestOperation`. + + @discussion When `enqueueHTTPRequestOperationWithRequest:success:failure` is invoked, each registered class is consulted in turn to see if it can handle the specific request. The first class to return `YES` when sent a `canProcessRequest:` message is used to create an operation using `initWithURLRequest:` and do `setCompletionBlockWithSuccess:failure:`. There is no guarantee that all registered classes will be consulted. Classes are consulted in the reverse order of their registration. Attempting to register an already-registered class will move it to the top of the list. + + @see `AFHTTPClientOperation` + */ +- (BOOL)registerHTTPOperationClass:(Class)operationClass; + +/** + Unregisters the specified subclass of `AFHTTPRequestOperation`. + + @param The class conforming to the `AFHTTPClientOperation` protocol to unregister + + @discussion After this method is invoked, `operationClass` is no longer consulted when `requestWithMethod:path:parameters` is invoked. + */ +- (void)unregisterHTTPOperationClass:(Class)operationClass; + +///---------------------------------- +/// @name Managing HTTP Header Values +///---------------------------------- + +/** + Returns the value for the HTTP headers set in request objects created by the HTTP client. + + @param header The HTTP header to return the default value for + + @return The default value for the HTTP header, or `nil` if unspecified + */ +- (NSString *)defaultValueForHeader:(NSString *)header; + +/** + Sets the value for the HTTP headers set in request objects made by the HTTP client. If `nil`, removes the existing value for that header. + + @param header The HTTP header to set a default value for + @param value The value set as default for the specified header, or `nil + */ +- (void)setDefaultHeader:(NSString *)header value:(NSString *)value; + +/** + Sets the "Authorization" HTTP header set in request objects made by the HTTP client to a basic authentication value with Base64-encoded username and password. This overwrites any existing value for this header. + + @param username The HTTP basic auth username + @param password The HTTP basic auth password + */ +- (void)setAuthorizationHeaderWithUsername:(NSString *)username password:(NSString *)password; + +/** + Sets the "Authorization" HTTP header set in request objects made by the HTTP client to a token-based authentication value, such as an OAuth access token. This overwrites any existing value for this header. + + @param token The authentication token + */ +- (void)setAuthorizationHeaderWithToken:(NSString *)token; + +/** + Clears any existing value for the "Authorization" HTTP header. + */ +- (void)clearAuthorizationHeader; + +///------------------------------- +/// @name Creating Request Objects +///------------------------------- + +/** + Creates an `NSMutableURLRequest` object with the specified HTTP method and path. + + If the HTTP method is `GET`, the parameters will be used to construct a url-encoded query string that is appended to the request's URL. Otherwise, the parameters will be encoded according to the value of the `parameterEncoding` property, and set as the request body. + + @param method The HTTP method for the request, such as `GET`, `POST`, `PUT`, or `DELETE`. + @param path The path to be appended to the HTTP client's base URL and used as the request URL. + @param parameters The parameters to be either set as a query string for `GET` requests, or the request HTTP body. + + @return An `NSMutableURLRequest` object + */ +- (NSMutableURLRequest *)requestWithMethod:(NSString *)method + path:(NSString *)path + parameters:(NSDictionary *)parameters; + +/** + Creates an `NSMutableURLRequest` object with the specified HTTP method and path, and constructs a `multipart/form-data` HTTP body, using the specified parameters and multipart form data block. See http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.2 + + @param method The HTTP method for the request. Must be either `POST`, `PUT`, or `DELETE`. + @param path The path to be appended to the HTTP client's base URL and used as the request URL. + @param parameters The parameters to be encoded and set in the request HTTP body. + @param block A block that takes a single argument and appends data to the HTTP body. The block argument is an object adopting the `AFMultipartFormData` protocol. This can be used to upload files, encode HTTP body as JSON or XML, or specify multiple values for the same parameter, as one might for array values. + + @discussion The multipart form data is constructed synchronously in the specified block, so in cases where large amounts of data are being added to the request, you should consider performing this method in the background. Likewise, the form data is constructed in-memory, so it may be advantageous to instead write parts of the form data to a file and stream the request body using the `HTTPBodyStream` property of `NSURLRequest`. + + @warning An exception will be raised if the specified method is not `POST`, `PUT` or `DELETE`. + + @return An `NSMutableURLRequest` object + */ +- (NSMutableURLRequest *)multipartFormRequestWithMethod:(NSString *)method + path:(NSString *)path + parameters:(NSDictionary *)parameters + constructingBodyWithBlock:(void (^)(id formData))block; + +///------------------------------- +/// @name Creating HTTP Operations +///------------------------------- + +/** + Creates an `AFHTTPRequestOperation`. + + In order to determine what kind of operation is created, each registered subclass conforming to the `AFHTTPClient` protocol is consulted (in reverse order of when they were specified) to see if it can handle the specific request. The first class to return `YES` when sent a `canProcessRequest:` message is used to generate an operation using `HTTPRequestOperationWithRequest:success:failure:`. + + @param request The request object to be loaded asynchronously during execution of the operation. + @param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the created request operation and the object created from the response data of request. + @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the resonse data. This block has no return value and takes two arguments:, the created request operation and the `NSError` object describing the network or parsing error that occurred. + */ +- (AFHTTPRequestOperation *)HTTPRequestOperationWithRequest:(NSURLRequest *)request + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure; + +///---------------------------------------- +/// @name Managing Enqueued HTTP Operations +///---------------------------------------- + +/** + Enqueues an `AFHTTPRequestOperation` to the HTTP client's operation queue. + + @param operation The HTTP request operation to be enqueued. + */ +- (void)enqueueHTTPRequestOperation:(AFHTTPRequestOperation *)operation; + +/** + Cancels all operations in the HTTP client's operation queue whose URLs match the specified HTTP method and path. + + @param method The HTTP method to match for the cancelled requests, such as `GET`, `POST`, `PUT`, or `DELETE`. If `nil`, all request operations with URLs matching the path will be cancelled. + @param url The path to match for the cancelled requests. + */ +- (void)cancelAllHTTPOperationsWithMethod:(NSString *)method path:(NSString *)path; + +///--------------------------------------- +/// @name Batching HTTP Request Operations +///--------------------------------------- + +/** + Creates and enqueues an `AFHTTPRequestOperation` to the HTTP client's operation queue for each specified request object into a batch. When each request operation finishes, the specified progress block is executed, until all of the request operations have finished, at which point the completion block also executes. + + @param requests The `NSURLRequest` objects used to create and enqueue operations. + @param progressBlock A block object to be executed upon the completion of each request operation in the batch. This block has no return value and takes two arguments: the number of operations that have already finished execution, and the total number of operations. + @param completionBlock A block object to be executed upon the completion of all of the request operations in the batch. This block has no return value and takes a single argument: the batched request operations. + + @discussion Operations are created by passing the specified `NSURLRequest` objects in `requests`, using `-HTTPRequestOperationWithRequest:success:failure:`, with `nil` for both the `success` and `failure` parameters. + */ +- (void)enqueueBatchOfHTTPRequestOperationsWithRequests:(NSArray *)requests + progressBlock:(void (^)(NSUInteger numberOfCompletedOperations, NSUInteger totalNumberOfOperations))progressBlock + completionBlock:(void (^)(NSArray *operations))completionBlock; + +/** + Enqueues the specified request operations into a batch. When each request operation finishes, the specified progress block is executed, until all of the request operations have finished, at which point the completion block also executes. + + @param operations The request operations used to be batched and enqueued. + @param progressBlock A block object to be executed upon the completion of each request operation in the batch. This block has no return value and takes two arguments: the number of operations that have already finished execution, and the total number of operations. + @param completionBlock A block object to be executed upon the completion of all of the request operations in the batch. This block has no return value and takes a single argument: the batched request operations. + */ +- (void)enqueueBatchOfHTTPRequestOperations:(NSArray *)operations + progressBlock:(void (^)(NSUInteger numberOfCompletedOperations, NSUInteger totalNumberOfOperations))progressBlock + completionBlock:(void (^)(NSArray *operations))completionBlock; + +///--------------------------- +/// @name Making HTTP Requests +///--------------------------- + +/** + Creates an `AFHTTPRequestOperation` with a `GET` request, and enqueues it to the HTTP client's operation queue. + + @param path The path to be appended to the HTTP client's base URL and used as the request URL. + @param parameters The parameters to be encoded and appended as the query string for the request URL. + @param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the created request operation and the object created from the response data of request. + @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the resonse data. This block has no return value and takes two arguments:, the created request operation and the `NSError` object describing the network or parsing error that occurred. + + @see HTTPRequestOperationWithRequest:success:failure + */ +- (void)getPath:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure; + +/** + Creates an `AFHTTPRequestOperation` with a `POST` request, and enqueues it to the HTTP client's operation queue. + + @param path The path to be appended to the HTTP client's base URL and used as the request URL. + @param parameters The parameters to be encoded and set in the request HTTP body. + @param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the created request operation and the object created from the response data of request. + @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the resonse data. This block has no return value and takes two arguments:, the created request operation and the `NSError` object describing the network or parsing error that occurred. + + @see HTTPRequestOperationWithRequest:success:failure + */ +- (void)postPath:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure; + +/** + Creates an `AFHTTPRequestOperation` with a `PUT` request, and enqueues it to the HTTP client's operation queue. + + @param path The path to be appended to the HTTP client's base URL and used as the request URL. + @param parameters The parameters to be encoded and set in the request HTTP body. + @param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the created request operation and the object created from the response data of request. + @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the resonse data. This block has no return value and takes two arguments:, the created request operation and the `NSError` object describing the network or parsing error that occurred. + + @see HTTPRequestOperationWithRequest:success:failure + */ +- (void)putPath:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure; + +/** + Creates an `AFHTTPRequestOperation` with a `DELETE` request, and enqueues it to the HTTP client's operation queue. + + @param path The path to be appended to the HTTP client's base URL and used as the request URL. + @param parameters The parameters to be encoded and set in the request HTTP body. + @param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the created request operation and the object created from the response data of request. + @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the resonse data. This block has no return value and takes two arguments:, the created request operation and the `NSError` object describing the network or parsing error that occurred. + + @see HTTPRequestOperationWithRequest:success:failure + */ +- (void)deletePath:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure; + +/** + Creates an `AFHTTPRequestOperation` with a `PATCH` request, and enqueues it to the HTTP client's operation queue. + + @param path The path to be appended to the HTTP client's base URL and used as the request URL. + @param parameters The parameters to be encoded and set in the request HTTP body. + @param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the created request operation and the object created from the response data of request. + @param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the resonse data. This block has no return value and takes two arguments:, the created request operation and the `NSError` object describing the network or parsing error that occurred. + + @see HTTPRequestOperationWithRequest:success:failure + */ +- (void)patchPath:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure; +@end + +#pragma mark - + +/** + The `AFMultipartFormData` protocol defines the methods supported by the parameter in the block argument of `multipartFormRequestWithMethod:path:parameters:constructingBodyWithBlock:`. + + @see `AFHTTPClient -multipartFormRequestWithMethod:path:parameters:constructingBodyWithBlock:` + */ +@protocol AFMultipartFormData + +/** + Appends HTTP headers, followed by the encoded data and the multipart form boundary. + + @param headers The HTTP headers to be appended to the form data. + @param body The data to be encoded and appended to the form data. + */ +- (void)appendPartWithHeaders:(NSDictionary *)headers body:(NSData *)body; + +/** + Appends the HTTP headers `Content-Disposition: form-data; name=#{name}"`, followed by the encoded data and the multipart form boundary. + + @param data The data to be encoded and appended to the form data. + @param name The name to be associated with the specified data. This parameter must not be `nil`. + */ +- (void)appendPartWithFormData:(NSData *)data name:(NSString *)name; + +/** + Appends the HTTP header `Content-Disposition: file; filename=#{filename}; name=#{name}"` and `Content-Type: #{mimeType}`, followed by the encoded file data and the multipart form boundary. + + @param data The data to be encoded and appended to the form data. + @param name The name to be associated with the specified data. This parameter must not be `nil`. + @param mimeType The MIME type of the specified data. (For example, the MIME type for a JPEG image is image/jpeg.) For a list of valid MIME types, see http://www.iana.org/assignments/media-types/. This parameter must not be `nil`. + @param filename The filename to be associated with the specified data. This parameter must not be `nil`. + */ +- (void)appendPartWithFileData:(NSData *)data name:(NSString *)name fileName:(NSString *)fileName mimeType:(NSString *)mimeType; + +/** + Appends the HTTP header `Content-Disposition: file; filename=#{generated filename}; name=#{name}"` and `Content-Type: #{generated mimeType}`, followed by the encoded file data and the multipart form boundary. + + @param fileURL The URL corresponding to the file whose content will be appended to the form. + @param name The name to be associated with the specified data. This parameter must not be `nil`. + @param error If an error occurs, upon return contains an `NSError` object that describes the problem. + + @return `YES` if the file data was successfully appended, otherwise `NO`. + + @discussion The filename and MIME type for this data in the form will be automatically generated, using `NSURLResponse` `-suggestedFilename` and `-MIMEType`, respectively. + */ +- (BOOL)appendPartWithFileURL:(NSURL *)fileURL name:(NSString *)name error:(NSError **)error; + +/** + Appends encoded data to the form data. + + @param data The data to be encoded and appended to the form data. + */ +- (void)appendData:(NSData *)data; + +/** + Appends a string to the form data. + + @param string The string to be encoded and appended to the form data. + */ +- (void)appendString:(NSString *)string; + +@end + diff --git a/AFNetworking/AFHTTPClient.m b/AFNetworking/AFHTTPClient.m new file mode 100644 index 0000000..b375c51 --- /dev/null +++ b/AFNetworking/AFHTTPClient.m @@ -0,0 +1,793 @@ +// AFHTTPClient.m +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import + +#import "AFHTTPClient.h" +#import "AFHTTPRequestOperation.h" +#import "AFJSONUtilities.h" + +#import + +#if __IPHONE_OS_VERSION_MIN_REQUIRED +#import +#endif + +#ifdef _SYSTEMCONFIGURATION_H +#import +#import +#import +#import +#import +#import +#endif + +NSString * const AFNetworkingReachabilityDidChangeNotification = @"com.alamofire.networking.reachability.change"; + +static NSString * const kAFMultipartFormLineDelimiter = @"\r\n"; // CRLF +static NSString * const kAFMultipartFormBoundary = @"Boundary+0xAbCdEfGbOuNdArY"; + +@interface AFMultipartFormData : NSObject { +@private + NSStringEncoding _stringEncoding; + NSMutableData *_mutableData; +} + +@property (readonly) NSData *data; + +- (id)initWithStringEncoding:(NSStringEncoding)encoding; + +@end + +#pragma mark - + +#ifdef _SYSTEMCONFIGURATION_H +typedef SCNetworkReachabilityRef AFNetworkReachabilityRef; +typedef void (^AFNetworkReachabilityStatusBlock)(AFNetworkReachabilityStatus status); +#else +typedef id AFNetworkReachabilityRef; +#endif + +typedef void (^AFCompletionBlock)(void); + +static NSUInteger const kAFHTTPClientDefaultMaxConcurrentOperationCount = 4; + +static NSString * AFBase64EncodedStringFromString(NSString *string) { + NSData *data = [NSData dataWithBytes:[string UTF8String] length:[string lengthOfBytesUsingEncoding:NSUTF8StringEncoding]]; + NSUInteger length = [data length]; + NSMutableData *mutableData = [NSMutableData dataWithLength:((length + 2) / 3) * 4]; + + uint8_t *input = (uint8_t *)[data bytes]; + uint8_t *output = (uint8_t *)[mutableData mutableBytes]; + + for (NSUInteger i = 0; i < length; i += 3) { + NSUInteger value = 0; + for (NSUInteger j = i; j < (i + 3); j++) { + value <<= 8; + if (j < length) { + value |= (0xFF & input[j]); + } + } + + static uint8_t const kAFBase64EncodingTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + NSUInteger idx = (i / 3) * 4; + output[idx + 0] = kAFBase64EncodingTable[(value >> 18) & 0x3F]; + output[idx + 1] = kAFBase64EncodingTable[(value >> 12) & 0x3F]; + output[idx + 2] = (i + 1) < length ? kAFBase64EncodingTable[(value >> 6) & 0x3F] : '='; + output[idx + 3] = (i + 2) < length ? kAFBase64EncodingTable[(value >> 0) & 0x3F] : '='; + } + + return [[[NSString alloc] initWithData:mutableData encoding:NSASCIIStringEncoding] autorelease]; +} + +NSString * AFURLEncodedStringFromStringWithEncoding(NSString *string, NSStringEncoding encoding) { + static NSString * const kAFLegalCharactersToBeEscaped = @"?!@#$^&%*+=,:;'\"`<>()[]{}/\\|~ "; + + /* + The documentation for `CFURLCreateStringByAddingPercentEscapes` suggests that one should "pre-process" URL strings with unpredictable sequences that may already contain percent escapes. However, if the string contains an unescaped sequence with '%' appearing without an escape code (such as when representing percentages like "42%"), `stringByReplacingPercentEscapesUsingEncoding` will return `nil`. Thus, the string is only unescaped if there are no invalid percent-escaped sequences. + */ + NSString *unescapedString = [string stringByReplacingPercentEscapesUsingEncoding:encoding]; + if (unescapedString) { + string = unescapedString; + } + + return [(NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)string, NULL, (CFStringRef)kAFLegalCharactersToBeEscaped, CFStringConvertNSStringEncodingToEncoding(encoding)) autorelease]; +} + +#pragma mark - + +@interface AFQueryStringComponent : NSObject { +@private + NSString *_key; + NSString *_value; +} + +@property (readwrite, nonatomic, retain) id key; +@property (readwrite, nonatomic, retain) id value; + +- (id)initWithKey:(id)key value:(id)value; +- (NSString *)URLEncodedStringValueWithEncoding:(NSStringEncoding)stringEncoding; + +@end + +@implementation AFQueryStringComponent +@synthesize key = _key; +@synthesize value = _value; + +- (id)initWithKey:(id)key value:(id)value { + self = [super init]; + if (!self) { + return nil; + } + + self.key = key; + self.value = value; + + return self; +} + +- (void)dealloc { + [_key release]; + [_value release]; + [super dealloc]; +} + +- (NSString *)URLEncodedStringValueWithEncoding:(NSStringEncoding)stringEncoding { + return [NSString stringWithFormat:@"%@=%@", self.key, AFURLEncodedStringFromStringWithEncoding([self.value description], stringEncoding)]; +} + +@end + +#pragma mark - + +extern NSArray * AFQueryStringComponentsFromKeyAndValue(NSString *key, id value); +extern NSArray * AFQueryStringComponentsFromKeyAndDictionaryValue(NSString *key, NSDictionary *value); +extern NSArray * AFQueryStringComponentsFromKeyAndArrayValue(NSString *key, NSArray *value); + +NSString * AFQueryStringFromParametersWithEncoding(NSDictionary *parameters, NSStringEncoding stringEncoding) { + NSMutableArray *mutableComponents = [NSMutableArray array]; + for (AFQueryStringComponent *component in AFQueryStringComponentsFromKeyAndValue(nil, parameters)) { + [mutableComponents addObject:[component URLEncodedStringValueWithEncoding:stringEncoding]]; + } + + return [mutableComponents componentsJoinedByString:@"&"]; +} + +NSArray * AFQueryStringComponentsFromKeyAndValue(NSString *key, id value) { + NSMutableArray *mutableQueryStringComponents = [NSMutableArray array]; + + if([value isKindOfClass:[NSDictionary class]]) { + [mutableQueryStringComponents addObjectsFromArray:AFQueryStringComponentsFromKeyAndDictionaryValue(key, value)]; + } else if([value isKindOfClass:[NSArray class]]) { + [mutableQueryStringComponents addObjectsFromArray:AFQueryStringComponentsFromKeyAndArrayValue(key, value)]; + } else { + [mutableQueryStringComponents addObject:[[[AFQueryStringComponent alloc] initWithKey:key value:value] autorelease]]; + } + + return mutableQueryStringComponents; +} + +NSArray * AFQueryStringComponentsFromKeyAndDictionaryValue(NSString *key, NSDictionary *value){ + NSMutableArray *mutableQueryStringComponents = [NSMutableArray array]; + + [value enumerateKeysAndObjectsUsingBlock:^(id nestedKey, id nestedValue, BOOL *stop) { + [mutableQueryStringComponents addObjectsFromArray:AFQueryStringComponentsFromKeyAndValue((key ? [NSString stringWithFormat:@"%@[%@]", key, nestedKey] : nestedKey), nestedValue)]; + }]; + + return mutableQueryStringComponents; +} + +NSArray * AFQueryStringComponentsFromKeyAndArrayValue(NSString *key, NSArray *value) { + NSMutableArray *mutableQueryStringComponents = [NSMutableArray array]; + + [value enumerateObjectsUsingBlock:^(id nestedValue, NSUInteger idx, BOOL *stop) { + [mutableQueryStringComponents addObjectsFromArray:AFQueryStringComponentsFromKeyAndValue([NSString stringWithFormat:@"%@[]", key], nestedValue)]; + }]; + + return mutableQueryStringComponents; +} + +static NSString * AFJSONStringFromParameters(NSDictionary *parameters) { + NSError *error = nil; + NSData *JSONData = AFJSONEncode(parameters, &error); + + if (!error) { + return [[[NSString alloc] initWithData:JSONData encoding:NSUTF8StringEncoding] autorelease]; + } else { + return nil; + } +} + +static NSString * AFPropertyListStringFromParameters(NSDictionary *parameters) { + NSString *propertyListString = nil; + NSError *error = nil; + + NSData *propertyListData = [NSPropertyListSerialization dataWithPropertyList:parameters format:NSPropertyListXMLFormat_v1_0 options:0 error:&error]; + if (!error) { + propertyListString = [[[NSString alloc] initWithData:propertyListData encoding:NSUTF8StringEncoding] autorelease]; + } + + return propertyListString; +} + +@interface AFHTTPClient () +@property (readwrite, nonatomic, retain) NSURL *baseURL; +@property (readwrite, nonatomic, retain) NSMutableArray *registeredHTTPOperationClassNames; +@property (readwrite, nonatomic, retain) NSMutableDictionary *defaultHeaders; +@property (readwrite, nonatomic, retain) NSOperationQueue *operationQueue; +#ifdef _SYSTEMCONFIGURATION_H +@property (readwrite, nonatomic, assign) AFNetworkReachabilityRef networkReachability; +@property (readwrite, nonatomic, assign) AFNetworkReachabilityStatus networkReachabilityStatus; +@property (readwrite, nonatomic, copy) AFNetworkReachabilityStatusBlock networkReachabilityStatusBlock; +#endif + +#ifdef _SYSTEMCONFIGURATION_H +- (void)startMonitoringNetworkReachability; +- (void)stopMonitoringNetworkReachability; +#endif +@end + +@implementation AFHTTPClient +@synthesize baseURL = _baseURL; +@synthesize stringEncoding = _stringEncoding; +@synthesize parameterEncoding = _parameterEncoding; +@synthesize registeredHTTPOperationClassNames = _registeredHTTPOperationClassNames; +@synthesize defaultHeaders = _defaultHeaders; +@synthesize operationQueue = _operationQueue; +#ifdef _SYSTEMCONFIGURATION_H +@synthesize networkReachability = _networkReachability; +@synthesize networkReachabilityStatus = _networkReachabilityStatus; +@synthesize networkReachabilityStatusBlock = _networkReachabilityStatusBlock; +#endif + ++ (AFHTTPClient *)clientWithBaseURL:(NSURL *)url { + return [[[self alloc] initWithBaseURL:url] autorelease]; +} + +- (id)initWithBaseURL:(NSURL *)url { + self = [super init]; + if (!self) { + return nil; + } + + self.baseURL = url; + + self.stringEncoding = NSUTF8StringEncoding; + self.parameterEncoding = AFFormURLParameterEncoding; + + self.registeredHTTPOperationClassNames = [NSMutableArray array]; + + self.defaultHeaders = [NSMutableDictionary dictionary]; + + // Accept-Encoding HTTP Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3 + [self setDefaultHeader:@"Accept-Encoding" value:@"gzip"]; + + // Accept-Language HTTP Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4 + NSString *preferredLanguageCodes = [[NSLocale preferredLanguages] componentsJoinedByString:@", "]; + [self setDefaultHeader:@"Accept-Language" value:[NSString stringWithFormat:@"%@, en-us;q=0.8", preferredLanguageCodes]]; + +#if __IPHONE_OS_VERSION_MIN_REQUIRED + // User-Agent Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.43 + [self setDefaultHeader:@"User-Agent" value:[NSString stringWithFormat:@"%@/%@ (%@, %@ %@, %@, Scale/%f)", [[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString *)kCFBundleIdentifierKey], [[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString *)kCFBundleVersionKey], @"unknown", [[UIDevice currentDevice] systemName], [[UIDevice currentDevice] systemVersion], [[UIDevice currentDevice] model], ([[UIScreen mainScreen] respondsToSelector:@selector(scale)] ? [[UIScreen mainScreen] scale] : 1.0)]]; +#elif __MAC_OS_X_VERSION_MIN_REQUIRED + [self setDefaultHeader:@"User-Agent" value:[NSString stringWithFormat:@"%@/%@ (%@)", [[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString *)kCFBundleIdentifierKey], [[[NSBundle mainBundle] infoDictionary] objectForKey:(NSString *)kCFBundleVersionKey], @"unknown"]]; +#endif + +#ifdef _SYSTEMCONFIGURATION_H + self.networkReachabilityStatus = AFNetworkReachabilityStatusUnknown; + [self startMonitoringNetworkReachability]; +#endif + + self.operationQueue = [[[NSOperationQueue alloc] init] autorelease]; + [self.operationQueue setMaxConcurrentOperationCount:kAFHTTPClientDefaultMaxConcurrentOperationCount]; + + return self; +} + +- (void)dealloc { +#ifdef _SYSTEMCONFIGURATION_H + [self stopMonitoringNetworkReachability]; + [_networkReachabilityStatusBlock release]; +#endif + + [_baseURL release]; + [_registeredHTTPOperationClassNames release]; + [_defaultHeaders release]; + [_operationQueue release]; + + [super dealloc]; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@: %p, baseURL: %@, defaultHeaders: %@, registeredOperationClasses: %@, operationQueue: %@>", NSStringFromClass([self class]), self, [self.baseURL absoluteString], self.defaultHeaders, self.registeredHTTPOperationClassNames, self.operationQueue]; +} + +#pragma mark - + +#ifdef _SYSTEMCONFIGURATION_H +static BOOL AFURLHostIsIPAddress(NSURL *url) { + struct sockaddr_in sa_in; + struct sockaddr_in6 sa_in6; + + return [url host] && (inet_pton(AF_INET, [[url host] UTF8String], &sa_in) == 1 || inet_pton(AF_INET6, [[url host] UTF8String], &sa_in6) == 1); +} + +static AFNetworkReachabilityStatus AFNetworkReachabilityStatusForFlags(SCNetworkReachabilityFlags flags) { + BOOL isReachable = ((flags & kSCNetworkReachabilityFlagsReachable) != 0); + BOOL needsConnection = ((flags & kSCNetworkReachabilityFlagsConnectionRequired) != 0); + BOOL isNetworkReachable = (isReachable && !needsConnection); + + AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusUnknown; + if(isNetworkReachable == NO){ + status = AFNetworkReachabilityStatusNotReachable; + } +#if TARGET_OS_IPHONE + else if((flags & kSCNetworkReachabilityFlagsIsWWAN) != 0){ + status = AFNetworkReachabilityStatusReachableViaWWAN; + } +#endif + else { + status = AFNetworkReachabilityStatusReachableViaWiFi; + } + + return status; +} + +static void AFNetworkReachabilityCallback(SCNetworkReachabilityRef __unused target, SCNetworkReachabilityFlags flags, void *info) { + AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusForFlags(flags); + AFNetworkReachabilityStatusBlock block = (AFNetworkReachabilityStatusBlock)info; + if (block) { + block(status); + } + + [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingReachabilityDidChangeNotification object:[NSNumber numberWithInt:status]]; +} + +static const void * AFNetworkReachabilityRetainCallback(const void *info) { + return [(AFNetworkReachabilityStatusBlock)info copy]; +} + +static void AFNetworkReachabilityReleaseCallback(const void *info) { + [(AFNetworkReachabilityStatusBlock)info release]; +} + +- (void)startMonitoringNetworkReachability { + [self stopMonitoringNetworkReachability]; + + if (!self.baseURL) { + return; + } + + self.networkReachability = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, [[self.baseURL host] UTF8String]); + + AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status){ + self.networkReachabilityStatus = status; + if (self.networkReachabilityStatusBlock) { + self.networkReachabilityStatusBlock(status); + } + }; + + SCNetworkReachabilityContext context = {0, callback, AFNetworkReachabilityRetainCallback, AFNetworkReachabilityReleaseCallback, NULL}; + SCNetworkReachabilitySetCallback(self.networkReachability, AFNetworkReachabilityCallback, &context); + SCNetworkReachabilityScheduleWithRunLoop(self.networkReachability, CFRunLoopGetMain(), (CFStringRef)NSRunLoopCommonModes); + + /* Network reachability monitoring does not establish a baseline for IP addresses as it does for hostnames, so if the base URL host is an IP address, the initial reachability callback is manually triggered. + */ + if (AFURLHostIsIPAddress(self.baseURL)) { + SCNetworkReachabilityFlags flags; + SCNetworkReachabilityGetFlags(self.networkReachability, &flags); + dispatch_async(dispatch_get_main_queue(), ^{ + AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusForFlags(flags); + callback(status); + }); + } +} + +- (void)stopMonitoringNetworkReachability { + if (_networkReachability) { + SCNetworkReachabilityUnscheduleFromRunLoop(_networkReachability, CFRunLoopGetMain(), (CFStringRef)NSRunLoopCommonModes); + CFRelease(_networkReachability); + } +} + +- (void)setReachabilityStatusChangeBlock:(void (^)(AFNetworkReachabilityStatus status))block { + self.networkReachabilityStatusBlock = block; +} +#endif + +#pragma mark - + +- (BOOL)registerHTTPOperationClass:(Class)operationClass { + if (![operationClass isSubclassOfClass:[AFHTTPRequestOperation class]]) { + return NO; + } + + NSString *className = NSStringFromClass(operationClass); + [self.registeredHTTPOperationClassNames removeObject:className]; + [self.registeredHTTPOperationClassNames insertObject:className atIndex:0]; + + return YES; +} + +- (void)unregisterHTTPOperationClass:(Class)operationClass { + NSString *className = NSStringFromClass(operationClass); + [self.registeredHTTPOperationClassNames removeObject:className]; +} + +#pragma mark - + +- (NSString *)defaultValueForHeader:(NSString *)header { + return [self.defaultHeaders valueForKey:header]; +} + +- (void)setDefaultHeader:(NSString *)header value:(NSString *)value { + [self.defaultHeaders setValue:value forKey:header]; +} + +- (void)setAuthorizationHeaderWithUsername:(NSString *)username password:(NSString *)password { + NSString *basicAuthCredentials = [NSString stringWithFormat:@"%@:%@", username, password]; + [self setDefaultHeader:@"Authorization" value:[NSString stringWithFormat:@"Basic %@", AFBase64EncodedStringFromString(basicAuthCredentials)]]; +} + +- (void)setAuthorizationHeaderWithToken:(NSString *)token { + [self setDefaultHeader:@"Authorization" value:[NSString stringWithFormat:@"Token token=\"%@\"", token]]; +} + +- (void)clearAuthorizationHeader { + [self.defaultHeaders removeObjectForKey:@"Authorization"]; +} + +#pragma mark - + +- (NSMutableURLRequest *)requestWithMethod:(NSString *)method + path:(NSString *)path + parameters:(NSDictionary *)parameters +{ + NSURL *url = [NSURL URLWithString:path relativeToURL:self.baseURL]; + NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] initWithURL:url] autorelease]; + [request setHTTPMethod:method]; + [request setAllHTTPHeaderFields:self.defaultHeaders]; + + if (parameters) { + if ([method isEqualToString:@"GET"] || [method isEqualToString:@"HEAD"] || [method isEqualToString:@"DELETE"]) { + url = [NSURL URLWithString:[[url absoluteString] stringByAppendingFormat:[path rangeOfString:@"?"].location == NSNotFound ? @"?%@" : @"&%@", AFQueryStringFromParametersWithEncoding(parameters, self.stringEncoding)]]; + [request setURL:url]; + } else { + NSString *charset = (NSString *)CFStringConvertEncodingToIANACharSetName(CFStringConvertNSStringEncodingToEncoding(self.stringEncoding)); + switch (self.parameterEncoding) { + case AFFormURLParameterEncoding:; + [request setValue:[NSString stringWithFormat:@"application/x-www-form-urlencoded; charset=%@", charset] forHTTPHeaderField:@"Content-Type"]; + [request setHTTPBody:[AFQueryStringFromParametersWithEncoding(parameters, self.stringEncoding) dataUsingEncoding:self.stringEncoding]]; + break; + case AFJSONParameterEncoding:; + [request setValue:[NSString stringWithFormat:@"application/json; charset=%@", charset] forHTTPHeaderField:@"Content-Type"]; + [request setHTTPBody:[AFJSONStringFromParameters(parameters) dataUsingEncoding:self.stringEncoding]]; + break; + case AFPropertyListParameterEncoding:; + [request setValue:[NSString stringWithFormat:@"application/x-plist; charset=%@", charset] forHTTPHeaderField:@"Content-Type"]; + [request setHTTPBody:[AFPropertyListStringFromParameters(parameters) dataUsingEncoding:self.stringEncoding]]; + break; + } + } + } + + return request; +} + +- (NSMutableURLRequest *)multipartFormRequestWithMethod:(NSString *)method + path:(NSString *)path + parameters:(NSDictionary *)parameters + constructingBodyWithBlock:(void (^)(id formData))block +{ + NSMutableURLRequest *request = [self requestWithMethod:method path:path parameters:nil]; + __block AFMultipartFormData *formData = [[AFMultipartFormData alloc] initWithStringEncoding:self.stringEncoding]; + + for (AFQueryStringComponent *component in AFQueryStringComponentsFromKeyAndValue(nil, parameters)) { + NSData *data = nil; + if ([component.value isKindOfClass:[NSData class]]) { + data = component.value; + } else { + data = [[component.value description] dataUsingEncoding:self.stringEncoding]; + } + + [formData appendPartWithFormData:data name:[component.key description]]; + } + + if (block) { + block(formData); + } + + [request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@", kAFMultipartFormBoundary] forHTTPHeaderField:@"Content-Type"]; + [request setHTTPBody:[formData data]]; + + [formData autorelease]; + + return request; +} + +- (AFHTTPRequestOperation *)HTTPRequestOperationWithRequest:(NSURLRequest *)urlRequest + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure +{ + AFHTTPRequestOperation *operation = nil; + NSString *className = nil; + NSEnumerator *enumerator = [self.registeredHTTPOperationClassNames reverseObjectEnumerator]; + while (!operation && (className = [enumerator nextObject])) { + Class op_class = NSClassFromString(className); + if (op_class && [op_class canProcessRequest:urlRequest]) { + operation = [[(AFHTTPRequestOperation *)[op_class alloc] initWithRequest:urlRequest] autorelease]; + } + } + + if (!operation) { + operation = [[[AFHTTPRequestOperation alloc] initWithRequest:urlRequest] autorelease]; + } + + [operation setCompletionBlockWithSuccess:success failure:failure]; + + return operation; +} + +#pragma mark - + +- (void)enqueueHTTPRequestOperation:(AFHTTPRequestOperation *)operation { + [self.operationQueue addOperation:operation]; +} + +- (void)cancelAllHTTPOperationsWithMethod:(NSString *)method path:(NSString *)path { + for (NSOperation *operation in [self.operationQueue operations]) { + if (![operation isKindOfClass:[AFHTTPRequestOperation class]]) { + continue; + } + + if ((!method || [method isEqualToString:[[(AFHTTPRequestOperation *)operation request] HTTPMethod]]) && [path isEqualToString:[[[(AFHTTPRequestOperation *)operation request] URL] path]]) { + [operation cancel]; + } + } +} + +- (void)enqueueBatchOfHTTPRequestOperationsWithRequests:(NSArray *)requests + progressBlock:(void (^)(NSUInteger numberOfCompletedOperations, NSUInteger totalNumberOfOperations))progressBlock + completionBlock:(void (^)(NSArray *operations))completionBlock +{ + NSMutableArray *mutableOperations = [NSMutableArray array]; + for (NSURLRequest *request in requests) { + AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:nil failure:nil]; + [mutableOperations addObject:operation]; + } + + [self enqueueBatchOfHTTPRequestOperations:mutableOperations progressBlock:progressBlock completionBlock:completionBlock]; +} + +- (void)enqueueBatchOfHTTPRequestOperations:(NSArray *)operations + progressBlock:(void (^)(NSUInteger numberOfCompletedOperations, NSUInteger totalNumberOfOperations))progressBlock + completionBlock:(void (^)(NSArray *operations))completionBlock +{ + __block dispatch_group_t dispatchGroup = dispatch_group_create(); + dispatch_retain(dispatchGroup); + NSBlockOperation *batchedOperation = [NSBlockOperation blockOperationWithBlock:^{ + dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^{ + if (completionBlock) { + completionBlock(operations); + } + }); + dispatch_release(dispatchGroup); + }]; + + NSPredicate *finishedOperationPredicate = [NSPredicate predicateWithFormat:@"isFinished == YES"]; + + for (AFHTTPRequestOperation *operation in operations) { + AFCompletionBlock originalCompletionBlock = [[operation.completionBlock copy] autorelease]; + operation.completionBlock = ^{ + dispatch_queue_t queue = operation.successCallbackQueue ? operation.successCallbackQueue : dispatch_get_main_queue(); + dispatch_group_async(dispatchGroup, queue, ^{ + if (originalCompletionBlock) { + originalCompletionBlock(); + } + + if (progressBlock) { + progressBlock([[operations filteredArrayUsingPredicate:finishedOperationPredicate] count], [operations count]); + } + + dispatch_group_leave(dispatchGroup); + }); + }; + + dispatch_group_enter(dispatchGroup); + [batchedOperation addDependency:operation]; + + [self enqueueHTTPRequestOperation:operation]; + } + [self.operationQueue addOperation:batchedOperation]; +} + +#pragma mark - + +- (void)getPath:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure +{ + NSURLRequest *request = [self requestWithMethod:@"GET" path:path parameters:parameters]; + AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:success failure:failure]; + [self enqueueHTTPRequestOperation:operation]; +} + +- (void)postPath:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure +{ + NSURLRequest *request = [self requestWithMethod:@"POST" path:path parameters:parameters]; + AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:success failure:failure]; + [self enqueueHTTPRequestOperation:operation]; +} + +- (void)putPath:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure +{ + NSURLRequest *request = [self requestWithMethod:@"PUT" path:path parameters:parameters]; + AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:success failure:failure]; + [self enqueueHTTPRequestOperation:operation]; +} + +- (void)deletePath:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure +{ + NSURLRequest *request = [self requestWithMethod:@"DELETE" path:path parameters:parameters]; + AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:success failure:failure]; + [self enqueueHTTPRequestOperation:operation]; +} + +- (void)patchPath:(NSString *)path + parameters:(NSDictionary *)parameters + success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure +{ + NSURLRequest *request = [self requestWithMethod:@"PATCH" path:path parameters:parameters]; + AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:success failure:failure]; + [self enqueueHTTPRequestOperation:operation]; +} + +@end + +#pragma mark - + +static NSString * const kAFMultipartFormCRLF = @"\r\n"; + +static inline NSString * AFMultipartFormInitialBoundary() { + return [NSString stringWithFormat:@"--%@%@", kAFMultipartFormBoundary, kAFMultipartFormCRLF]; +} + +static inline NSString * AFMultipartFormEncapsulationBoundary() { + return [NSString stringWithFormat:@"%@--%@%@", kAFMultipartFormCRLF, kAFMultipartFormBoundary, kAFMultipartFormCRLF]; +} + +static inline NSString * AFMultipartFormFinalBoundary() { + return [NSString stringWithFormat:@"%@--%@--%@%@", kAFMultipartFormCRLF, kAFMultipartFormBoundary, kAFMultipartFormCRLF, kAFMultipartFormCRLF]; +} + +@interface AFMultipartFormData () +@property (readwrite, nonatomic, assign) NSStringEncoding stringEncoding; +@property (readwrite, nonatomic, retain) NSMutableData *mutableData; +@end + +@implementation AFMultipartFormData +@synthesize stringEncoding = _stringEncoding; +@synthesize mutableData = _mutableData; + +- (id)initWithStringEncoding:(NSStringEncoding)encoding { + self = [super init]; + if (!self) { + return nil; + } + + self.stringEncoding = encoding; + self.mutableData = [NSMutableData dataWithLength:0]; + + return self; +} + +- (void)dealloc { + [_mutableData release]; + [super dealloc]; +} + +- (NSData *)data { + NSMutableData *finalizedData = [NSMutableData dataWithData:self.mutableData]; + [finalizedData appendData:[AFMultipartFormFinalBoundary() dataUsingEncoding:self.stringEncoding]]; + return finalizedData; +} + +#pragma mark - AFMultipartFormData + +- (void)appendPartWithHeaders:(NSDictionary *)headers body:(NSData *)body { + if ([self.mutableData length] == 0) { + [self appendString:AFMultipartFormInitialBoundary()]; + } else { + [self appendString:AFMultipartFormEncapsulationBoundary()]; + } + + for (NSString *field in [headers allKeys]) { + [self appendString:[NSString stringWithFormat:@"%@: %@%@", field, [headers valueForKey:field], kAFMultipartFormCRLF]]; + } + + [self appendString:kAFMultipartFormCRLF]; + [self appendData:body]; +} + +- (void)appendPartWithFormData:(NSData *)data name:(NSString *)name { + NSMutableDictionary *mutableHeaders = [NSMutableDictionary dictionary]; + [mutableHeaders setValue:[NSString stringWithFormat:@"form-data; name=\"%@\"", name] forKey:@"Content-Disposition"]; + + [self appendPartWithHeaders:mutableHeaders body:data]; +} + +- (void)appendPartWithFileData:(NSData *)data name:(NSString *)name fileName:(NSString *)fileName mimeType:(NSString *)mimeType { + NSMutableDictionary *mutableHeaders = [NSMutableDictionary dictionary]; + [mutableHeaders setValue:[NSString stringWithFormat:@"form-data; name=\"%@\"; filename=\"%@\"", name, fileName] forKey:@"Content-Disposition"]; + [mutableHeaders setValue:mimeType forKey:@"Content-Type"]; + + [self appendPartWithHeaders:mutableHeaders body:data]; +} + +- (BOOL)appendPartWithFileURL:(NSURL *)fileURL name:(NSString *)name error:(NSError **)error { + if (![fileURL isFileURL]) { + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + [userInfo setValue:fileURL forKey:NSURLErrorFailingURLErrorKey]; + [userInfo setValue:NSLocalizedString(@"Expected URL to be a file URL", nil) forKey:NSLocalizedFailureReasonErrorKey]; + if (error != NULL) { + *error = [[[NSError alloc] initWithDomain:AFNetworkingErrorDomain code:NSURLErrorBadURL userInfo:userInfo] autorelease]; + } + + return NO; + } + + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:fileURL]; + [request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData]; + + NSURLResponse *response = nil; + NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:error]; + + if (data && response) { + [self appendPartWithFileData:data name:name fileName:[response suggestedFilename] mimeType:[response MIMEType]]; + + return YES; + } else { + return NO; + } +} + +- (void)appendData:(NSData *)data { + [self.mutableData appendData:data]; +} + +- (void)appendString:(NSString *)string { + [self appendData:[string dataUsingEncoding:self.stringEncoding]]; +} + +@end diff --git a/AFNetworking/AFHTTPRequestOperation.h b/AFNetworking/AFHTTPRequestOperation.h new file mode 100644 index 0000000..9cab0e5 --- /dev/null +++ b/AFNetworking/AFHTTPRequestOperation.h @@ -0,0 +1,154 @@ +// AFHTTPRequestOperation.h +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "AFURLConnectionOperation.h" + +/** + Returns a set of MIME types detected in an HTTP `Accept` or `Content-Type` header. + */ +extern NSSet * AFContentTypesFromHTTPHeader(NSString *string); + +extern NSString * AFCreateIncompleteDownloadDirectoryPath(void); + +/** + `AFHTTPRequestOperation` is a subclass of `AFURLConnectionOperation` for requests using the HTTP or HTTPS protocols. It encapsulates the concept of acceptable status codes and content types, which determine the success or failure of a request. + */ +@interface AFHTTPRequestOperation : AFURLConnectionOperation + +///---------------------------------------------- +/// @name Getting HTTP URL Connection Information +///---------------------------------------------- + +/** + The last HTTP response received by the operation's connection. + */ +@property (readonly, nonatomic, retain) NSHTTPURLResponse *response; + +/** + Set a target file for the response, will stream directly into this destination. + Defaults to nil, which will use a memory stream. Will create a new outputStream on change. + + Note: Changing this while the request is not in ready state will be ignored. + */ +@property (nonatomic, copy) NSString *responseFilePath; + + +/** + Expected total length. This is different than expectedContentLength if the file is resumed. + On regular requests, this is equal to self.response.expectedContentLength unless we resume a request. + + Note: this can also be -1 if the file size is not sent (*) + */ +@property (assign, readonly) long long totalContentLength; + +/** + Indicator for the file offset on partial/resumed downloads. + This is greater than zero if the file download is resumed. + */ +@property (assign, readonly) long long offsetContentLength; + + +///---------------------------------------------------------- +/// @name Managing And Checking For Acceptable HTTP Responses +///---------------------------------------------------------- + +/** + A Boolean value that corresponds to whether the status code of the response is within the specified set of acceptable status codes. Returns `YES` if `acceptableStatusCodes` is `nil`. + */ +@property (readonly) BOOL hasAcceptableStatusCode; + +/** + A Boolean value that corresponds to whether the MIME type of the response is among the specified set of acceptable content types. Returns `YES` if `acceptableContentTypes` is `nil`. + */ +@property (readonly) BOOL hasAcceptableContentType; + +/** + The callback dispatch queue on success. If `NULL` (default), the main queue is used. + */ +@property (nonatomic) dispatch_queue_t successCallbackQueue; + +/** + The callback dispatch queue on failure. If `NULL` (default), the main queue is used. + */ +@property (nonatomic) dispatch_queue_t failureCallbackQueue; + +///------------------------------------------------------------- +/// @name Managing Accceptable HTTP Status Codes & Content Types +///------------------------------------------------------------- + +/** + Returns an `NSIndexSet` object containing the ranges of acceptable HTTP status codes. When non-`nil`, the operation will set the `error` property to an error in `AFErrorDomain`. See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html + + By default, this is the range 200 to 299, inclusive. + */ ++ (NSIndexSet *)acceptableStatusCodes; + +/** + Adds status codes to the set of acceptable HTTP status codes returned by `+acceptableStatusCodes` in subsequent calls by this class and its descendents. + + @param statusCodes The status codes to be added to the set of acceptable HTTP status codes + */ ++ (void)addAcceptableStatusCodes:(NSIndexSet *)statusCodes; + +/** + Returns an `NSSet` object containing the acceptable MIME types. When non-`nil`, the operation will set the `error` property to an error in `AFErrorDomain`. See http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17 + + By default, this is `nil`. + */ ++ (NSSet *)acceptableContentTypes; + +/** + Adds content types to the set of acceptable MIME types returned by `+acceptableContentTypes` in subsequent calls by this class and its descendents. + + @param contentTypes The content types to be added to the set of acceptable MIME types + */ ++ (void)addAcceptableContentTypes:(NSSet *)contentTypes; + + +///----------------------------------------------------- +/// @name Determining Whether A Request Can Be Processed +///----------------------------------------------------- + +/** + A Boolean value determining whether or not the class can process the specified request. For example, `AFJSONRequestOperation` may check to make sure the content type was `application/json` or the URL path extension was `.json`. + + @param urlRequest The request that is determined to be supported or not supported for this class. + */ ++ (BOOL)canProcessRequest:(NSURLRequest *)urlRequest; + +///----------------------------------------------------------- +/// @name Setting Completion Block Success / Failure Callbacks +///----------------------------------------------------------- + +/** + Sets the `completionBlock` property with a block that executes either the specified success or failure block, depending on the state of the request on completion. If `error` returns a value, which can be caused by an unacceptable status code or content type, then `failure` is executed. Otherwise, `success` is executed. + + @param success The block to be executed on the completion of a successful request. This block has no return value and takes two arguments: the receiver operation and the object constructed from the response data of the request. + @param failure The block to be executed on the completion of an unsuccessful request. This block has no return value and takes two arguments: the receiver operation and the error that occured during the request. + + @discussion This method should be overridden in subclasses in order to specify the response object passed into the success block. + */ +- (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure; + +@end diff --git a/AFNetworking/AFHTTPRequestOperation.m b/AFNetworking/AFHTTPRequestOperation.m new file mode 100644 index 0000000..bc9b2b7 --- /dev/null +++ b/AFNetworking/AFHTTPRequestOperation.m @@ -0,0 +1,335 @@ +// AFHTTPRequestOperation.m +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "AFHTTPRequestOperation.h" +#import + +NSString * const kAFNetworkingIncompleteDownloadDirectoryName = @"Incomplete"; + +NSSet * AFContentTypesFromHTTPHeader(NSString *string) { + static NSCharacterSet *_skippedCharacterSet = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + _skippedCharacterSet = [[NSCharacterSet characterSetWithCharactersInString:@" ,"] retain]; + }); + + if (!string) { + return nil; + } + + NSScanner *scanner = [NSScanner scannerWithString:string]; + scanner.charactersToBeSkipped = _skippedCharacterSet; + + NSMutableSet *mutableContentTypes = [NSMutableSet set]; + while (![scanner isAtEnd]) { + NSString *contentType = nil; + if ([scanner scanUpToString:@";" intoString:&contentType]) { + [scanner scanUpToString:@"," intoString:nil]; + } + + if (contentType) { + [mutableContentTypes addObject:contentType]; + } + } + + return [NSSet setWithSet:mutableContentTypes]; +} + +static void AFSwizzleClassMethodWithImplementation(Class klass, SEL selector, IMP implementation) { + Method originalMethod = class_getClassMethod(klass, selector); + if (method_getImplementation(originalMethod) != implementation) { + class_replaceMethod(objc_getMetaClass([NSStringFromClass(klass) UTF8String]), selector, implementation, method_getTypeEncoding(originalMethod)); + } +} + +static NSString * AFStringFromIndexSet(NSIndexSet *indexSet) { + NSMutableString *string = [NSMutableString string]; + + NSRange range = NSMakeRange([indexSet firstIndex], 1); + while (range.location != NSNotFound) { + NSUInteger nextIndex = [indexSet indexGreaterThanIndex:range.location]; + while (nextIndex == range.location + range.length) { + range.length++; + nextIndex = [indexSet indexGreaterThanIndex:nextIndex]; + } + + if (string.length) { + [string appendString:@","]; + } + + if (range.length == 1) { + [string appendFormat:@"%u", range.location]; + } else { + NSUInteger firstIndex = range.location; + NSUInteger lastIndex = firstIndex + range.length - 1; + [string appendFormat:@"%u-%u", firstIndex, lastIndex]; + } + + range.location = nextIndex; + range.length = 1; + } + + return string; +} + +NSString * AFCreateIncompleteDownloadDirectoryPath(void) { + static NSString *incompleteDownloadPath; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSString *tempDirectory = NSTemporaryDirectory(); + incompleteDownloadPath = [[tempDirectory stringByAppendingPathComponent:kAFNetworkingIncompleteDownloadDirectoryName] retain]; + + NSError *error = nil; + NSFileManager *fileMan = [[NSFileManager alloc] init]; + if(![fileMan createDirectoryAtPath:incompleteDownloadPath withIntermediateDirectories:YES attributes:nil error:&error]) { + NSLog(@"Failed to create incomplete downloads directory at %@", incompleteDownloadPath); + } + [fileMan release]; + }); + + return incompleteDownloadPath; +} + +#pragma mark - + +@interface AFHTTPRequestOperation () +@property (readwrite, nonatomic, retain) NSURLRequest *request; +@property (readwrite, nonatomic, retain) NSHTTPURLResponse *response; +@property (readwrite, nonatomic, retain) NSError *HTTPError; +@property (assign) long long totalContentLength; +@property (assign) long long offsetContentLength; +@end + +@implementation AFHTTPRequestOperation +@synthesize HTTPError = _HTTPError; +@synthesize responseFilePath = _responseFilePath; +@synthesize successCallbackQueue = _successCallbackQueue; +@synthesize failureCallbackQueue = _failureCallbackQueue; +@synthesize totalContentLength = _totalContentLength; +@synthesize offsetContentLength = _offsetContentLength; +@dynamic request; +@dynamic response; + +- (void)dealloc { + [_HTTPError release]; + + if (_successCallbackQueue) { + dispatch_release(_successCallbackQueue); + _successCallbackQueue = NULL; + } + + if (_failureCallbackQueue) { + dispatch_release(_failureCallbackQueue); + _failureCallbackQueue = NULL; + } + + [super dealloc]; +} + +- (NSError *)error { + if (self.response && !self.HTTPError) { + if (![self hasAcceptableStatusCode]) { + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + [userInfo setValue:[NSString stringWithFormat:NSLocalizedString(@"Expected status code in (%@), got %d", nil), AFStringFromIndexSet([[self class] acceptableStatusCodes]), [self.response statusCode]] forKey:NSLocalizedDescriptionKey]; + [userInfo setValue:[self.request URL] forKey:NSURLErrorFailingURLErrorKey]; + + self.HTTPError = [[[NSError alloc] initWithDomain:AFNetworkingErrorDomain code:NSURLErrorBadServerResponse userInfo:userInfo] autorelease]; + } else if ([self.responseData length] > 0 && ![self hasAcceptableContentType]) { // Don't invalidate content type if there is no content + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + [userInfo setValue:[NSString stringWithFormat:NSLocalizedString(@"Expected content type %@, got %@", nil), [[self class] acceptableContentTypes], [self.response MIMEType]] forKey:NSLocalizedDescriptionKey]; + [userInfo setValue:[self.request URL] forKey:NSURLErrorFailingURLErrorKey]; + + self.HTTPError = [[[NSError alloc] initWithDomain:AFNetworkingErrorDomain code:NSURLErrorCannotDecodeContentData userInfo:userInfo] autorelease]; + } + } + + if (self.HTTPError) { + return self.HTTPError; + } else { + return [super error]; + } +} + +- (void)pause { + unsigned long long offset = 0; + if ([self.outputStream propertyForKey:NSStreamFileCurrentOffsetKey]) { + offset = [[self.outputStream propertyForKey:NSStreamFileCurrentOffsetKey] unsignedLongLongValue]; + } else { + offset = [[self.outputStream propertyForKey:NSStreamDataWrittenToMemoryStreamKey] length]; + } + + NSMutableURLRequest *mutableURLRequest = [[self.request mutableCopy] autorelease]; + if ([[self.response allHeaderFields] valueForKey:@"ETag"]) { + [mutableURLRequest setValue:[[self.response allHeaderFields] valueForKey:@"ETag"] forHTTPHeaderField:@"If-Range"]; + } + [mutableURLRequest setValue:[NSString stringWithFormat:@"bytes=%llu-", offset] forHTTPHeaderField:@"Range"]; + self.request = mutableURLRequest; + + [super pause]; +} + +- (BOOL)hasAcceptableStatusCode { + return ![[self class] acceptableStatusCodes] || [[[self class] acceptableStatusCodes] containsIndex:[self.response statusCode]]; +} + +- (BOOL)hasAcceptableContentType { + return ![[self class] acceptableContentTypes] || [[[self class] acceptableContentTypes] containsObject:[self.response MIMEType]]; +} + +- (void)setSuccessCallbackQueue:(dispatch_queue_t)successCallbackQueue { + if (successCallbackQueue != _successCallbackQueue) { + if (_successCallbackQueue) { + dispatch_release(_successCallbackQueue); + _successCallbackQueue = NULL; + } + + if (successCallbackQueue) { + dispatch_retain(successCallbackQueue); + _successCallbackQueue = successCallbackQueue; + } + } +} + +- (void)setFailureCallbackQueue:(dispatch_queue_t)failureCallbackQueue { + if (failureCallbackQueue != _failureCallbackQueue) { + if (_failureCallbackQueue) { + dispatch_release(_failureCallbackQueue); + _failureCallbackQueue = NULL; + } + + if (failureCallbackQueue) { + dispatch_retain(failureCallbackQueue); + _failureCallbackQueue = failureCallbackQueue; + } + } +} + +- (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure +{ + self.completionBlock = ^ { + if ([self isCancelled]) { + return; + } + + if (self.error) { + if (failure) { + dispatch_async(self.failureCallbackQueue ? self.failureCallbackQueue : dispatch_get_main_queue(), ^{ + failure(self, self.error); + }); + } + } else { + if (success) { + dispatch_async(self.successCallbackQueue ? self.successCallbackQueue : dispatch_get_main_queue(), ^{ + success(self, self.responseData); + }); + } + } + }; +} + +- (void)setResponseFilePath:(NSString *)responseFilePath { + if ([self isReady] && responseFilePath != _responseFilePath) { + [_responseFilePath release]; + _responseFilePath = [responseFilePath retain]; + + if (responseFilePath) { + self.outputStream = [NSOutputStream outputStreamToFileAtPath:responseFilePath append:NO]; + }else { + self.outputStream = [NSOutputStream outputStreamToMemory]; + } + } +} + +#pragma mark - AFHTTPRequestOperation + +static id AFStaticClassValueImplementation(id self, SEL _cmd) { + return objc_getAssociatedObject([self class], _cmd); +} + ++ (NSIndexSet *)acceptableStatusCodes { + return [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 100)]; +} + ++ (void)addAcceptableStatusCodes:(NSIndexSet *)statusCodes { + NSMutableIndexSet *mutableStatusCodes = [[[NSMutableIndexSet alloc] initWithIndexSet:[self acceptableStatusCodes]] autorelease]; + [mutableStatusCodes addIndexes:statusCodes]; + SEL selector = @selector(acceptableStatusCodes); + AFSwizzleClassMethodWithImplementation([self class], selector, (IMP)AFStaticClassValueImplementation); + objc_setAssociatedObject([self class], selector, mutableStatusCodes, OBJC_ASSOCIATION_COPY_NONATOMIC); +} + ++ (NSSet *)acceptableContentTypes { + return nil; +} + ++ (void)addAcceptableContentTypes:(NSSet *)contentTypes { + NSMutableSet *mutableContentTypes = [[[NSMutableSet alloc] initWithSet:[self acceptableContentTypes] copyItems:YES] autorelease]; + [mutableContentTypes unionSet:contentTypes]; + SEL selector = @selector(acceptableContentTypes); + AFSwizzleClassMethodWithImplementation([self class], selector, (IMP)AFStaticClassValueImplementation); + objc_setAssociatedObject([self class], selector, mutableContentTypes, OBJC_ASSOCIATION_COPY_NONATOMIC); +} + ++ (BOOL)canProcessRequest:(NSURLRequest *)request { + if (![[self class] isEqual:[AFHTTPRequestOperation class]]) { + return YES; + } + + return [[self acceptableContentTypes] intersectsSet:AFContentTypesFromHTTPHeader([request valueForHTTPHeaderField:@"Accept"])]; +} + +#pragma mark - NSURLConnectionDelegate + +- (void)connection:(NSURLConnection *)connection +didReceiveResponse:(NSURLResponse *)response +{ + self.response = (NSHTTPURLResponse *)response; + + // 206 = Partial Content. + long long totalContentLength = self.response.expectedContentLength; + long long fileOffset = 0; + if ([self.response statusCode] != 206) { + if ([self.outputStream propertyForKey:NSStreamFileCurrentOffsetKey]) { + [self.outputStream setProperty:[NSNumber numberWithInteger:0] forKey:NSStreamFileCurrentOffsetKey]; + } else { + if ([[self.outputStream propertyForKey:NSStreamDataWrittenToMemoryStreamKey] length] > 0) { + self.outputStream = [NSOutputStream outputStreamToMemory]; + } + } + }else { + NSString *contentRange = [self.response.allHeaderFields valueForKey:@"Content-Range"]; + if ([contentRange hasPrefix:@"bytes"]) { + NSArray *bytes = [contentRange componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@" -/"]]; + if ([bytes count] == 4) { + fileOffset = [[bytes objectAtIndex:1] longLongValue]; + totalContentLength = [[bytes objectAtIndex:2] longLongValue] ?: -1; // if this is *, it's converted to 0, but -1 is default. + } + } + + } + self.offsetContentLength = MAX(fileOffset, 0); + self.totalContentLength = totalContentLength; + [self.outputStream open]; +} + +@end diff --git a/AFNetworking/AFImageRequestOperation.h b/AFNetworking/AFImageRequestOperation.h new file mode 100644 index 0000000..7a7f78a --- /dev/null +++ b/AFNetworking/AFImageRequestOperation.h @@ -0,0 +1,115 @@ +// AFImageRequestOperation.h +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "AFHTTPRequestOperation.h" + +#import + +#if __IPHONE_OS_VERSION_MIN_REQUIRED +#import +#elif __MAC_OS_X_VERSION_MIN_REQUIRED +#import +#endif + +/** + `AFImageRequestOperation` is a subclass of `AFHTTPRequestOperation` for downloading an processing images. + + ## Acceptable Content Types + + By default, `AFImageRequestOperation` accepts the following MIME types, which correspond to the image formats supported by UIImage or NSImage: + + - `image/tiff` + - `image/jpeg` + - `image/gif` + - `image/png` + - `image/ico` + - `image/x-icon` + - `image/bmp` + - `image/x-bmp` + - `image/x-xbitmap` + - `image/x-win-bitmap` + */ +@interface AFImageRequestOperation : AFHTTPRequestOperation + +/** + An image constructed from the response data. If an error occurs during the request, `nil` will be returned, and the `error` property will be set to the error. + */ +#if __IPHONE_OS_VERSION_MIN_REQUIRED +@property (readonly, nonatomic, retain) UIImage *responseImage; +#elif __MAC_OS_X_VERSION_MIN_REQUIRED +@property (readonly, nonatomic, retain) NSImage *responseImage; +#endif + +#if __IPHONE_OS_VERSION_MIN_REQUIRED +/** + The scale factor used when interpreting the image data to construct `responseImage`. Specifying a scale factor of 1.0 results in an image whose size matches the pixel-based dimensions of the image. Applying a different scale factor changes the size of the image as reported by the size property. This is set to the value of `[[UIScreen mainScreen] scale]` by default, which automatically scales images for retina displays, for instance. + */ +@property (nonatomic, assign) CGFloat imageScale; +#endif + +/** + An image constructed from the response data. If an error occurs during the request, `nil` will be returned, and the `error` property will be set to the error. + */ + +/** + Creates and returns an `AFImageRequestOperation` object and sets the specified success callback. + + @param urlRequest The request object to be loaded asynchronously during execution of the operation. + @param success A block object to be executed when the request finishes successfully. This block has no return value and takes a single arguments, the image created from the response data of the request. + + @return A new image request operation + */ +#if __IPHONE_OS_VERSION_MIN_REQUIRED ++ (AFImageRequestOperation *)imageRequestOperationWithRequest:(NSURLRequest *)urlRequest + success:(void (^)(UIImage *image))success; +#elif __MAC_OS_X_VERSION_MIN_REQUIRED ++ (AFImageRequestOperation *)imageRequestOperationWithRequest:(NSURLRequest *)urlRequest + success:(void (^)(NSImage *image))success; +#endif + +/** + Creates and returns an `AFImageRequestOperation` object and sets the specified success callback. + + @param urlRequest The request object to be loaded asynchronously during execution of the operation. + @param imageProcessingBlock A block object to be executed after the image request finishes successfully, but before the image is returned in the `success` block. This block takes a single argument, the image loaded from the response body, and returns the processed image. + @param cacheName The cache name to be associated with the image. `AFImageCache` associates objects by URL and cache name, allowing for multiple versions of the same image to be cached. + @param success A block object to be executed when the request finishes successfully, with a status code in the 2xx range, and with an acceptable content type (e.g. `image/png`). This block has no return value and takes three arguments: the request object of the operation, the response for the request, and the image created from the response data. + @param failure A block object to be executed when the request finishes unsuccessfully. This block has no return value and takes three arguments: the request object of the operation, the response for the request, and the error associated with the cause for the unsuccessful operation. + + @return A new image request operation + */ +#if __IPHONE_OS_VERSION_MIN_REQUIRED ++ (AFImageRequestOperation *)imageRequestOperationWithRequest:(NSURLRequest *)urlRequest + imageProcessingBlock:(UIImage *(^)(UIImage *))imageProcessingBlock + cacheName:(NSString *)cacheNameOrNil + success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image))success + failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error))failure; +#elif __MAC_OS_X_VERSION_MIN_REQUIRED ++ (AFImageRequestOperation *)imageRequestOperationWithRequest:(NSURLRequest *)urlRequest + imageProcessingBlock:(NSImage *(^)(NSImage *))imageProcessingBlock + cacheName:(NSString *)cacheNameOrNil + success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSImage *image))success + failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error))failure; +#endif + +@end diff --git a/AFNetworking/AFImageRequestOperation.m b/AFNetworking/AFImageRequestOperation.m new file mode 100644 index 0000000..3821046 --- /dev/null +++ b/AFNetworking/AFImageRequestOperation.m @@ -0,0 +1,238 @@ +// AFImageRequestOperation.m +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "AFImageRequestOperation.h" + +static dispatch_queue_t af_image_request_operation_processing_queue; +static dispatch_queue_t image_request_operation_processing_queue() { + if (af_image_request_operation_processing_queue == NULL) { + af_image_request_operation_processing_queue = dispatch_queue_create("com.alamofire.networking.image-request.processing", 0); + } + + return af_image_request_operation_processing_queue; +} + +@interface AFImageRequestOperation () +#if __IPHONE_OS_VERSION_MIN_REQUIRED +@property (readwrite, nonatomic, retain) UIImage *responseImage; +#elif __MAC_OS_X_VERSION_MIN_REQUIRED +@property (readwrite, nonatomic, retain) NSImage *responseImage; +#endif +@end + +@implementation AFImageRequestOperation +@synthesize responseImage = _responseImage; +#if __IPHONE_OS_VERSION_MIN_REQUIRED +@synthesize imageScale = _imageScale; +#endif + +#if __IPHONE_OS_VERSION_MIN_REQUIRED ++ (AFImageRequestOperation *)imageRequestOperationWithRequest:(NSURLRequest *)urlRequest + success:(void (^)(UIImage *image))success +{ + return [self imageRequestOperationWithRequest:urlRequest imageProcessingBlock:nil cacheName:nil success:^(NSURLRequest __unused *request, NSHTTPURLResponse __unused *response, UIImage *image) { + if (success) { + success(image); + } + } failure:nil]; +} +#elif __MAC_OS_X_VERSION_MIN_REQUIRED ++ (AFImageRequestOperation *)imageRequestOperationWithRequest:(NSURLRequest *)urlRequest + success:(void (^)(NSImage *image))success +{ + return [self imageRequestOperationWithRequest:urlRequest imageProcessingBlock:nil cacheName:nil success:^(NSURLRequest __unused *request, NSHTTPURLResponse __unused *response, NSImage *image) { + if (success) { + success(image); + } + } failure:nil]; +} +#endif + + +#if __IPHONE_OS_VERSION_MIN_REQUIRED ++ (AFImageRequestOperation *)imageRequestOperationWithRequest:(NSURLRequest *)urlRequest + imageProcessingBlock:(UIImage *(^)(UIImage *))imageProcessingBlock + cacheName:(NSString *)cacheNameOrNil + success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image))success + failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error))failure +{ + AFImageRequestOperation *requestOperation = [[[AFImageRequestOperation alloc] initWithRequest:urlRequest] autorelease]; + [requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { + if (success) { + UIImage *image = responseObject; + if (imageProcessingBlock) { + dispatch_async(image_request_operation_processing_queue(), ^(void) { + UIImage *processedImage = imageProcessingBlock(image); + + dispatch_async(dispatch_get_main_queue(), ^(void) { + success(operation.request, operation.response, processedImage); + }); + }); + } else { + success(operation.request, operation.response, image); + } + } + } failure:^(AFHTTPRequestOperation *operation, NSError *error) { + if (failure) { + failure(operation.request, operation.response, error); + } + }]; + + + return requestOperation; +} +#elif __MAC_OS_X_VERSION_MIN_REQUIRED ++ (AFImageRequestOperation *)imageRequestOperationWithRequest:(NSURLRequest *)urlRequest + imageProcessingBlock:(NSImage *(^)(NSImage *))imageProcessingBlock + cacheName:(NSString *)cacheNameOrNil + success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSImage *image))success + failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error))failure +{ + AFImageRequestOperation *requestOperation = [[[AFImageRequestOperation alloc] initWithRequest:urlRequest] autorelease]; + [requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { + if (success) { + NSImage *image = responseObject; + if (imageProcessingBlock) { + dispatch_async(image_request_operation_processing_queue(), ^(void) { + NSImage *processedImage = imageProcessingBlock(image); + + dispatch_async(dispatch_get_main_queue(), ^(void) { + success(operation.request, operation.response, processedImage); + }); + }); + } else { + success(operation.request, operation.response, image); + } + } + } failure:^(AFHTTPRequestOperation *operation, NSError *error) { + if (failure) { + failure(operation.request, operation.response, error); + } + }]; + + return requestOperation; +} +#endif + +- (id)initWithRequest:(NSURLRequest *)urlRequest { + self = [super initWithRequest:urlRequest]; + if (!self) { + return nil; + } + +#if __IPHONE_OS_VERSION_MIN_REQUIRED + self.imageScale = [[UIScreen mainScreen] scale]; +#endif + + return self; +} + +- (void)dealloc { + [_responseImage release]; + [super dealloc]; +} + +#if __IPHONE_OS_VERSION_MIN_REQUIRED +- (UIImage *)responseImage { + if (!_responseImage && [self.responseData length] > 0 && [self isFinished]) { + UIImage *image = [UIImage imageWithData:self.responseData]; + + self.responseImage = [UIImage imageWithCGImage:[image CGImage] scale:self.imageScale orientation:image.imageOrientation]; + } + + return _responseImage; +} + +- (void)setImageScale:(CGFloat)imageScale { + if (imageScale == _imageScale) { + return; + } + + _imageScale = imageScale; + + self.responseImage = nil; +} +#elif __MAC_OS_X_VERSION_MIN_REQUIRED +- (NSImage *)responseImage { + if (!_responseImage && [self.responseData length] > 0 && [self isFinished]) { + // Ensure that the image is set to it's correct pixel width and height + NSBitmapImageRep *bitimage = [[NSBitmapImageRep alloc] initWithData:self.responseData]; + self.responseImage = [[[NSImage alloc] initWithSize:NSMakeSize([bitimage pixelsWide], [bitimage pixelsHigh])] autorelease]; + [self.responseImage addRepresentation:bitimage]; + [bitimage release]; + } + + return _responseImage; +} +#endif + +#pragma mark - AFHTTPClientOperation + ++ (NSSet *)acceptableContentTypes { + return [NSSet setWithObjects:@"image/tiff", @"image/jpeg", @"image/gif", @"image/png", @"image/ico", @"image/x-icon", @"image/bmp", @"image/x-bmp", @"image/x-xbitmap", @"image/x-win-bitmap", nil]; +} + ++ (BOOL)canProcessRequest:(NSURLRequest *)request { + static NSSet * _acceptablePathExtension = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + _acceptablePathExtension = [[NSSet alloc] initWithObjects:@"tif", @"tiff", @"jpg", @"jpeg", @"gif", @"png", @"ico", @"bmp", @"cur", nil]; + }); + + return [_acceptablePathExtension containsObject:[[request URL] pathExtension]] || [super canProcessRequest:request]; +} + +- (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure +{ + self.completionBlock = ^ { + if ([self isCancelled]) { + return; + } + + dispatch_async(image_request_operation_processing_queue(), ^(void) { + if (self.error) { + if (failure) { + dispatch_async(self.failureCallbackQueue ? self.failureCallbackQueue : dispatch_get_main_queue(), ^{ + failure(self, self.error); + }); + } + } else { + if (success) { +#if __IPHONE_OS_VERSION_MIN_REQUIRED + UIImage *image = nil; +#elif __MAC_OS_X_VERSION_MIN_REQUIRED + NSImage *image = nil; +#endif + + image = self.responseImage; + + dispatch_async(self.successCallbackQueue ? self.successCallbackQueue : dispatch_get_main_queue(), ^{ + success(self, image); + }); + } + } + }); + }; +} + +@end diff --git a/AFNetworking/AFJSONRequestOperation.h b/AFNetworking/AFJSONRequestOperation.h new file mode 100644 index 0000000..a1191f9 --- /dev/null +++ b/AFNetworking/AFJSONRequestOperation.h @@ -0,0 +1,66 @@ +// AFJSONRequestOperation.h +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "AFHTTPRequestOperation.h" + +/** + `AFJSONRequestOperation` is a subclass of `AFHTTPRequestOperation` for downloading and working with JSON response data. + + ## Acceptable Content Types + + By default, `AFJSONRequestOperation` accepts the following MIME types, which includes the official standard, `application/json`, as well as other commonly-used types: + + - `application/json` + - `text/json` + + @warning JSON parsing will automatically use JSONKit, SBJSON, YAJL, or NextiveJSON, if provided. Otherwise, the built-in `NSJSONSerialization` class is used, if available (iOS 5.0 and Mac OS 10.7). If the build target does not either support `NSJSONSerialization` or include a third-party JSON library, a runtime exception will be thrown when attempting to parse a JSON request. + */ +@interface AFJSONRequestOperation : AFHTTPRequestOperation + +///---------------------------- +/// @name Getting Response Data +///---------------------------- + +/** + A JSON object constructed from the response data. If an error occurs while parsing, `nil` will be returned, and the `error` property will be set to the error. + */ +@property (readonly, nonatomic, retain) id responseJSON; + +///---------------------------------- +/// @name Creating Request Operations +///---------------------------------- + +/** + Creates and returns an `AFJSONRequestOperation` object and sets the specified success and failure callbacks. + + @param urlRequest The request object to be loaded asynchronously during execution of the operation + @param success A block object to be executed when the operation finishes successfully. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the JSON object created from the response data of request. + @param failure A block object to be executed when the operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the resonse data as JSON. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the error describing the network or parsing error that occurred. + + @return A new JSON request operation + */ ++ (AFJSONRequestOperation *)JSONRequestOperationWithRequest:(NSURLRequest *)urlRequest + success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, id JSON))success + failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON))failure; + +@end diff --git a/AFNetworking/AFJSONRequestOperation.m b/AFNetworking/AFJSONRequestOperation.m new file mode 100644 index 0000000..bcdcb7f --- /dev/null +++ b/AFNetworking/AFJSONRequestOperation.m @@ -0,0 +1,138 @@ +// AFJSONRequestOperation.m +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "AFJSONRequestOperation.h" +#import "AFJSONUtilities.h" + +static dispatch_queue_t af_json_request_operation_processing_queue; +static dispatch_queue_t json_request_operation_processing_queue() { + if (af_json_request_operation_processing_queue == NULL) { + af_json_request_operation_processing_queue = dispatch_queue_create("com.alamofire.networking.json-request.processing", 0); + } + + return af_json_request_operation_processing_queue; +} + +@interface AFJSONRequestOperation () +@property (readwrite, nonatomic, retain) id responseJSON; +@property (readwrite, nonatomic, retain) NSError *JSONError; +@end + +@implementation AFJSONRequestOperation +@synthesize responseJSON = _responseJSON; +@synthesize JSONError = _JSONError; + ++ (AFJSONRequestOperation *)JSONRequestOperationWithRequest:(NSURLRequest *)urlRequest + success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, id JSON))success + failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON))failure +{ + AFJSONRequestOperation *requestOperation = [[[self alloc] initWithRequest:urlRequest] autorelease]; + [requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { + if (success) { + success(operation.request, operation.response, responseObject); + } + } failure:^(AFHTTPRequestOperation *operation, NSError *error) { + if (failure) { + failure(operation.request, operation.response, error, [(AFJSONRequestOperation *)operation responseJSON]); + } + }]; + + return requestOperation; +} + +- (void)dealloc { + [_responseJSON release]; + [_JSONError release]; + [super dealloc]; +} + +- (id)responseJSON { + if (!_responseJSON && [self.responseData length] > 0 && [self isFinished] && !self.JSONError) { + NSError *error = nil; + + if ([self.responseData length] == 0) { + self.responseJSON = nil; + } else { + self.responseJSON = AFJSONDecode(self.responseData, &error); + } + + self.JSONError = error; + } + + return _responseJSON; +} + +- (NSError *)error { + if (_JSONError) { + return _JSONError; + } else { + return [super error]; + } +} + +#pragma mark - AFHTTPRequestOperation + ++ (NSSet *)acceptableContentTypes { + return [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript", nil]; +} + ++ (BOOL)canProcessRequest:(NSURLRequest *)request { + return [[[request URL] pathExtension] isEqualToString:@"json"] || [super canProcessRequest:request]; +} + +- (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure +{ + self.completionBlock = ^ { + if ([self isCancelled]) { + return; + } + + if (self.error) { + if (failure) { + dispatch_async(self.failureCallbackQueue ? self.failureCallbackQueue : dispatch_get_main_queue(), ^{ + failure(self, self.error); + }); + } + } else { + dispatch_async(json_request_operation_processing_queue(), ^{ + id JSON = self.responseJSON; + + if (self.JSONError) { + if (failure) { + dispatch_async(self.failureCallbackQueue ? self.failureCallbackQueue : dispatch_get_main_queue(), ^{ + failure(self, self.error); + }); + } + } else { + if (success) { + dispatch_async(self.successCallbackQueue ? self.successCallbackQueue : dispatch_get_main_queue(), ^{ + success(self, JSON); + }); + } + } + }); + } + }; +} + +@end diff --git a/AFNetworking/AFJSONUtilities.h b/AFNetworking/AFJSONUtilities.h new file mode 100644 index 0000000..ece26a0 --- /dev/null +++ b/AFNetworking/AFJSONUtilities.h @@ -0,0 +1,26 @@ +// AFJSONUtilities.h +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import + +extern NSData * AFJSONEncode(id object, NSError **error); +extern id AFJSONDecode(NSData *data, NSError **error); diff --git a/AFNetworking/AFJSONUtilities.m b/AFNetworking/AFJSONUtilities.m new file mode 100644 index 0000000..3377fc4 --- /dev/null +++ b/AFNetworking/AFJSONUtilities.m @@ -0,0 +1,217 @@ +// AFJSONUtilities.m +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "AFJSONUtilities.h" + +NSData * AFJSONEncode(id object, NSError **error) { + NSData *data = nil; + + SEL _JSONKitSelector = NSSelectorFromString(@"JSONDataWithOptions:error:"); + SEL _YAJLSelector = NSSelectorFromString(@"yajl_JSONString"); + + id _SBJsonWriterClass = NSClassFromString(@"SBJsonWriter"); + SEL _SBJsonWriterSelector = NSSelectorFromString(@"dataWithObject:"); + + id _NXJsonSerializerClass = NSClassFromString(@"NXJsonSerializer"); + SEL _NXJsonSerializerSelector = NSSelectorFromString(@"serialize:"); + + id _NSJSONSerializationClass = NSClassFromString(@"NSJSONSerialization"); + SEL _NSJSONSerializationSelector = NSSelectorFromString(@"dataWithJSONObject:options:error:"); + +#ifdef _AFNETWORKING_PREFER_NSJSONSERIALIZATION_ + if (_NSJSONSerializationClass && [_NSJSONSerializationClass respondsToSelector:_NSJSONSerializationSelector]) { + goto _af_nsjson_encode; + } +#endif + + if (_JSONKitSelector && [object respondsToSelector:_JSONKitSelector]) { + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[object methodSignatureForSelector:_JSONKitSelector]]; + invocation.target = object; + invocation.selector = _JSONKitSelector; + + NSUInteger serializeOptionFlags = 0; + [invocation setArgument:&serializeOptionFlags atIndex:2]; // arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation + if (error != NULL) { + [invocation setArgument:error atIndex:3]; + } + + [invocation invoke]; + [invocation getReturnValue:&data]; + } else if (_SBJsonWriterClass && [_SBJsonWriterClass instancesRespondToSelector:_SBJsonWriterSelector]) { + id writer = [[_SBJsonWriterClass alloc] init]; + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[writer methodSignatureForSelector:_SBJsonWriterSelector]]; + invocation.target = writer; + invocation.selector = _SBJsonWriterSelector; + + [invocation setArgument:&object atIndex:2]; // arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation + + [invocation invoke]; + [invocation getReturnValue:&data]; + [writer release]; + } else if (_YAJLSelector && [object respondsToSelector:_YAJLSelector]) { + @try { + NSString *JSONString = nil; + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[object methodSignatureForSelector:_YAJLSelector]]; + invocation.target = object; + invocation.selector = _YAJLSelector; + + [invocation invoke]; + [invocation getReturnValue:&JSONString]; + + data = [JSONString dataUsingEncoding:NSUTF8StringEncoding]; + } + @catch (NSException *exception) { + *error = [[[NSError alloc] initWithDomain:NSStringFromClass([exception class]) code:0 userInfo:[exception userInfo]] autorelease]; + } + } else if (_NXJsonSerializerClass && [_NXJsonSerializerClass respondsToSelector:_NXJsonSerializerSelector]) { + NSString *JSONString = nil; + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[_NXJsonSerializerClass methodSignatureForSelector:_NXJsonSerializerSelector]]; + invocation.target = _NXJsonSerializerClass; + invocation.selector = _NXJsonSerializerSelector; + + [invocation setArgument:&object atIndex:2]; // arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation + + [invocation invoke]; + [invocation getReturnValue:&JSONString]; + data = [JSONString dataUsingEncoding:NSUTF8StringEncoding]; + } else if (_NSJSONSerializationClass && [_NSJSONSerializationClass respondsToSelector:_NSJSONSerializationSelector]) { +#ifdef _AFNETWORKING_PREFER_NSJSONSERIALIZATION_ + _af_nsjson_encode:; +#endif + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[_NSJSONSerializationClass methodSignatureForSelector:_NSJSONSerializationSelector]]; + invocation.target = _NSJSONSerializationClass; + invocation.selector = _NSJSONSerializationSelector; + + [invocation setArgument:&object atIndex:2]; // arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation + NSUInteger writeOptions = 0; + [invocation setArgument:&writeOptions atIndex:3]; + if (error != NULL) { + [invocation setArgument:error atIndex:4]; + } + + [invocation invoke]; + [invocation getReturnValue:&data]; + } else { + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:NSLocalizedString(@"Please either target a platform that supports NSJSONSerialization or add one of the following libraries to your project: JSONKit, SBJSON, or YAJL", nil) forKey:NSLocalizedRecoverySuggestionErrorKey]; + [[NSException exceptionWithName:NSInternalInconsistencyException reason:NSLocalizedString(@"No JSON generation functionality available", nil) userInfo:userInfo] raise]; + } + + return data; +} + +id AFJSONDecode(NSData *data, NSError **error) { + id JSON = nil; + + SEL _JSONKitSelector = NSSelectorFromString(@"objectFromJSONDataWithParseOptions:error:"); + SEL _YAJLSelector = NSSelectorFromString(@"yajl_JSONWithOptions:error:"); + + id _SBJSONParserClass = NSClassFromString(@"SBJsonParser"); + SEL _SBJSONParserSelector = NSSelectorFromString(@"objectWithData:"); + + id _NSJSONSerializationClass = NSClassFromString(@"NSJSONSerialization"); + SEL _NSJSONSerializationSelector = NSSelectorFromString(@"JSONObjectWithData:options:error:"); + + id _NXJsonParserClass = NSClassFromString(@"NXJsonParser"); + SEL _NXJsonParserSelector = NSSelectorFromString(@"parseData:error:ignoreNulls:"); + + +#ifdef _AFNETWORKING_PREFER_NSJSONSERIALIZATION_ + if (_NSJSONSerializationClass && [_NSJSONSerializationClass respondsToSelector:_NSJSONSerializationSelector]) { + goto _af_nsjson_decode; + } +#endif + + if (_JSONKitSelector && [data respondsToSelector:_JSONKitSelector]) { + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[data methodSignatureForSelector:_JSONKitSelector]]; + invocation.target = data; + invocation.selector = _JSONKitSelector; + + NSUInteger parseOptionFlags = 0; + [invocation setArgument:&parseOptionFlags atIndex:2]; // arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation + if (error != NULL) { + [invocation setArgument:&error atIndex:3]; + } + + [invocation invoke]; + [invocation getReturnValue:&JSON]; + } else if (_SBJSONParserClass && [_SBJSONParserClass instancesRespondToSelector:_SBJSONParserSelector]) { + id parser = [[_SBJSONParserClass alloc] init]; + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[parser methodSignatureForSelector:_SBJSONParserSelector]]; + invocation.target = parser; + invocation.selector = _SBJSONParserSelector; + + [invocation setArgument:&data atIndex:2]; // arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation + + [invocation invoke]; + [invocation getReturnValue:&JSON]; + [parser release]; + } else if (_YAJLSelector && [data respondsToSelector:_YAJLSelector]) { + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[data methodSignatureForSelector:_YAJLSelector]]; + invocation.target = data; + invocation.selector = _YAJLSelector; + + NSUInteger yajlParserOptions = 0; + [invocation setArgument:&yajlParserOptions atIndex:2]; // arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation + if (error != NULL) { + [invocation setArgument:&error atIndex:3]; + } + + [invocation invoke]; + [invocation getReturnValue:&JSON]; + } else if (_NXJsonParserClass && [_NXJsonParserClass respondsToSelector:_NXJsonParserSelector]) { + NSNumber *nullOption = [NSNumber numberWithBool:YES]; + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[_NXJsonParserClass methodSignatureForSelector:_NXJsonParserSelector]]; + invocation.target = _NXJsonParserClass; + invocation.selector = _NXJsonParserSelector; + + [invocation setArgument:&data atIndex:2]; // arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation + if (error != NULL) { + [invocation setArgument:&error atIndex:3]; + } + [invocation setArgument:&nullOption atIndex:4]; + + [invocation invoke]; + [invocation getReturnValue:&JSON]; + } else if (_NSJSONSerializationClass && [_NSJSONSerializationClass respondsToSelector:_NSJSONSerializationSelector]) { +#ifdef _AFNETWORKING_PREFER_NSJSONSERIALIZATION_ + _af_nsjson_decode:; +#endif + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[_NSJSONSerializationClass methodSignatureForSelector:_NSJSONSerializationSelector]]; + invocation.target = _NSJSONSerializationClass; + invocation.selector = _NSJSONSerializationSelector; + + [invocation setArgument:&data atIndex:2]; // arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation + NSUInteger readOptions = 0; + [invocation setArgument:&readOptions atIndex:3]; + if (error != NULL) { + [invocation setArgument:&error atIndex:4]; + } + + [invocation invoke]; + [invocation getReturnValue:&JSON]; + } else { + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:NSLocalizedString(@"Please either target a platform that supports NSJSONSerialization or add one of the following libraries to your project: JSONKit, SBJSON, or YAJL", nil) forKey:NSLocalizedRecoverySuggestionErrorKey]; + [[NSException exceptionWithName:NSInternalInconsistencyException reason:NSLocalizedString(@"No JSON parsing functionality available", nil) userInfo:userInfo] raise]; + } + + return JSON; +} diff --git a/AFNetworking/AFNetworkActivityIndicatorManager.h b/AFNetworking/AFNetworkActivityIndicatorManager.h new file mode 100644 index 0000000..4a5640c --- /dev/null +++ b/AFNetworking/AFNetworkActivityIndicatorManager.h @@ -0,0 +1,66 @@ +// AFNetworkActivityIndicatorManager.h +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import + +#import + +#if __IPHONE_OS_VERSION_MIN_REQUIRED +#import + +/** + `AFNetworkActivityIndicatorManager` manages the state of the network activity indicator in the status bar. When enabled, it will listen for notifications indicating that a network request operation has started or finished, and start or stop animating the indicator accordingly. The number of active requests is incremented and decremented much like a stack or a semaphore, and the activity indicator will animate so long as that number is greater than zero. + */ +@interface AFNetworkActivityIndicatorManager : NSObject + +/** + A Boolean value indicating whether the manager is enabled. + + @discussion If YES, the manager will change status bar network activity indicator according to network operation notifications it receives. The default value is NO. + */ +@property (nonatomic, assign, getter = isEnabled) BOOL enabled; + +/** + A Boolean value indicating whether the network activity indicator is currently displayed in the status bar. + */ +@property (readonly, nonatomic, assign) BOOL isNetworkActivityIndicatorVisible; + +/** + Returns the shared network activity indicator manager object for the system. + + @return The systemwide network activity indicator manager. + */ ++ (AFNetworkActivityIndicatorManager *)sharedManager; + +/** + Increments the number of active network requests. If this number was zero before incrementing, this will start animating the status bar network activity indicator. + */ +- (void)incrementActivityCount; + +/** + Decrements the number of active network requests. If this number becomes zero before decrementing, this will stop animating the status bar network activity indicator. + */ +- (void)decrementActivityCount; + +@end + +#endif diff --git a/AFNetworking/AFNetworkActivityIndicatorManager.m b/AFNetworking/AFNetworkActivityIndicatorManager.m new file mode 100644 index 0000000..01a6851 --- /dev/null +++ b/AFNetworking/AFNetworkActivityIndicatorManager.m @@ -0,0 +1,129 @@ +// AFNetworkActivityIndicatorManager.m +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "AFNetworkActivityIndicatorManager.h" + +#import "AFHTTPRequestOperation.h" +#import + +#if __IPHONE_OS_VERSION_MIN_REQUIRED +static NSTimeInterval const kAFNetworkActivityIndicatorInvisibilityDelay = 0.25; + +@interface AFNetworkActivityIndicatorManager () +@property (readwrite, nonatomic, assign) NSInteger activityCount; +@property (readwrite, nonatomic, retain) NSTimer *activityIndicatorVisibilityTimer; +@property (readonly, getter = isNetworkActivityIndicatorVisible) BOOL networkActivityIndicatorVisible; + +- (void)updateNetworkActivityIndicatorVisibility; +@end + +@implementation AFNetworkActivityIndicatorManager +@synthesize activityCount = _activityCount; +@synthesize activityIndicatorVisibilityTimer = _activityIndicatorVisibilityTimer; +@synthesize enabled = _enabled; +@dynamic networkActivityIndicatorVisible; + ++ (AFNetworkActivityIndicatorManager *)sharedManager { + static AFNetworkActivityIndicatorManager *_sharedManager = nil; + static dispatch_once_t oncePredicate; + dispatch_once(&oncePredicate, ^{ + _sharedManager = [[self alloc] init]; + }); + + return _sharedManager; +} + +- (id)init { + self = [super init]; + if (!self) { + return nil; + } + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(incrementActivityCount) name:AFNetworkingOperationDidStartNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(decrementActivityCount) name:AFNetworkingOperationDidFinishNotification object:nil]; + + return self; +} + +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; + + [_activityIndicatorVisibilityTimer invalidate]; + [_activityIndicatorVisibilityTimer release]; _activityIndicatorVisibilityTimer = nil; + + [super dealloc]; +} + +- (void)updateNetworkActivityIndicatorVisibilityDelayed { + if (self.enabled) { + // Delay hiding of activity indicator for a short interval, to avoid flickering + if (![self isNetworkActivityIndicatorVisible]) { + [self.activityIndicatorVisibilityTimer invalidate]; + self.activityIndicatorVisibilityTimer = [NSTimer timerWithTimeInterval:kAFNetworkActivityIndicatorInvisibilityDelay target:self selector:@selector(updateNetworkActivityIndicatorVisibility) userInfo:nil repeats:NO]; + [[NSRunLoop currentRunLoop] addTimer:self.activityIndicatorVisibilityTimer forMode:NSRunLoopCommonModes]; + } else { + [self updateNetworkActivityIndicatorVisibility]; + } + } +} + +- (BOOL)isNetworkActivityIndicatorVisible { + return _activityCount > 0; +} + +- (void)updateNetworkActivityIndicatorVisibility { + dispatch_async(dispatch_get_main_queue(), ^{ + [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:[self isNetworkActivityIndicatorVisible]]; + }); +} + +// Not exposed, but used if activityCount is set via KVC. +- (void)setActivityCount:(NSInteger)activityCount { + __sync_swap(&_activityCount, activityCount); + [self updateNetworkActivityIndicatorVisibilityDelayed]; +} + +- (void)incrementActivityCount { + [self willChangeValueForKey:@"activityCount"]; + OSAtomicIncrement32((int32_t*)&_activityCount); + [self didChangeValueForKey:@"activityCount"]; + [self updateNetworkActivityIndicatorVisibilityDelayed]; +} + +- (void)decrementActivityCount { + [self willChangeValueForKey:@"activityCount"]; + bool success; + do { + int32_t currentCount = _activityCount; + success = OSAtomicCompareAndSwap32(currentCount, MIN(currentCount - 1, currentCount), &_activityCount); + } while(!success); + [self didChangeValueForKey:@"activityCount"]; + [self updateNetworkActivityIndicatorVisibilityDelayed]; +} + ++ (NSSet *)keyPathsForValuesAffectingIsNetworkActivityIndicatorVisible { + return [NSSet setWithObject:@"activityCount"]; +} + +@end + +#endif diff --git a/AFNetworking/AFNetworking.h b/AFNetworking/AFNetworking.h new file mode 100644 index 0000000..49e596c --- /dev/null +++ b/AFNetworking/AFNetworking.h @@ -0,0 +1,44 @@ +// AFNetworking.h +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import + +#ifndef _AFNETWORKING_ +#define _AFNETWORKING_ + +#import "AFURLConnectionOperation.h" + +#import "AFHTTPRequestOperation.h" +#import "AFJSONRequestOperation.h" +#import "AFXMLRequestOperation.h" +#import "AFPropertyListRequestOperation.h" +#import "AFHTTPClient.h" + +#import "AFImageRequestOperation.h" + +#if __IPHONE_OS_VERSION_MIN_REQUIRED +#import "AFNetworkActivityIndicatorManager.h" +#import "UIImageView+AFNetworking.h" +#endif + +#endif /* _AFNETWORKING_ */ diff --git a/AFNetworking/AFPropertyListRequestOperation.h b/AFNetworking/AFPropertyListRequestOperation.h new file mode 100644 index 0000000..aa6e471 --- /dev/null +++ b/AFNetworking/AFPropertyListRequestOperation.h @@ -0,0 +1,68 @@ +// AFPropertyListRequestOperation.h +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "AFHTTPRequestOperation.h" + +/** + `AFPropertyListRequestOperation` is a subclass of `AFHTTPRequestOperation` for downloading and deserializing objects with property list (plist) response data. + + ## Acceptable Content Types + + By default, `AFPropertyListRequestOperation` accepts the following MIME types: + + - `application/x-plist` + */ +@interface AFPropertyListRequestOperation : AFHTTPRequestOperation + +///---------------------------- +/// @name Getting Response Data +///---------------------------- + +/** + An object deserialized from a plist constructed using the response data. + */ +@property (readonly, nonatomic, retain) id responsePropertyList; + +///-------------------------------------- +/// @name Managing Property List Behavior +///-------------------------------------- + +/** + One of the `NSPropertyListMutabilityOptions` options, specifying the mutability of objects deserialized from the property list. By default, this is `NSPropertyListImmutable`. + */ +@property (nonatomic, assign) NSPropertyListReadOptions propertyListReadOptions; + +/** + Creates and returns an `AFPropertyListRequestOperation` object and sets the specified success and failure callbacks. + + @param urlRequest The request object to be loaded asynchronously during execution of the operation + @param success A block object to be executed when the operation finishes successfully. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the object deserialized from a plist constructed using the response data. + @param failure A block object to be executed when the operation finishes unsuccessfully, or that finishes successfully, but encountered an error while deserializing the object from a property list. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the error describing the network or parsing error that occurred. + + @return A new property list request operation + */ ++ (AFPropertyListRequestOperation *)propertyListRequestOperationWithRequest:(NSURLRequest *)urlRequest + success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, id propertyList))success + failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id propertyList))failure; + +@end diff --git a/AFNetworking/AFPropertyListRequestOperation.m b/AFNetworking/AFPropertyListRequestOperation.m new file mode 100644 index 0000000..ecca1af --- /dev/null +++ b/AFNetworking/AFPropertyListRequestOperation.m @@ -0,0 +1,147 @@ +// AFPropertyListRequestOperation.m +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "AFPropertyListRequestOperation.h" + +static dispatch_queue_t af_property_list_request_operation_processing_queue; +static dispatch_queue_t property_list_request_operation_processing_queue() { + if (af_property_list_request_operation_processing_queue == NULL) { + af_property_list_request_operation_processing_queue = dispatch_queue_create("com.alamofire.networking.property-list-request.processing", 0); + } + + return af_property_list_request_operation_processing_queue; +} + +@interface AFPropertyListRequestOperation () +@property (readwrite, nonatomic, retain) id responsePropertyList; +@property (readwrite, nonatomic, assign) NSPropertyListFormat propertyListFormat; +@property (readwrite, nonatomic, retain) NSError *propertyListError; +@end + +@implementation AFPropertyListRequestOperation +@synthesize responsePropertyList = _responsePropertyList; +@synthesize propertyListReadOptions = _propertyListReadOptions; +@synthesize propertyListFormat = _propertyListFormat; +@synthesize propertyListError = _propertyListError; + ++ (AFPropertyListRequestOperation *)propertyListRequestOperationWithRequest:(NSURLRequest *)request + success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, id propertyList))success + failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id propertyList))failure +{ + AFPropertyListRequestOperation *requestOperation = [[[self alloc] initWithRequest:request] autorelease]; + [requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { + if (success) { + success(operation.request, operation.response, responseObject); + } + } failure:^(AFHTTPRequestOperation *operation, NSError *error) { + if (failure) { + failure(operation.request, operation.response, error, [(AFPropertyListRequestOperation *)operation responsePropertyList]); + } + }]; + + return requestOperation; +} + +- (id)initWithRequest:(NSURLRequest *)urlRequest { + self = [super initWithRequest:urlRequest]; + if (!self) { + return nil; + } + + self.propertyListReadOptions = NSPropertyListImmutable; + + return self; +} + +- (void)dealloc { + [_responsePropertyList release]; + [_propertyListError release]; + [super dealloc]; +} + +- (id)responsePropertyList { + if (!_responsePropertyList && [self.responseData length] > 0 && [self isFinished]) { + NSPropertyListFormat format; + NSError *error = nil; + self.responsePropertyList = [NSPropertyListSerialization propertyListWithData:self.responseData options:self.propertyListReadOptions format:&format error:&error]; + self.propertyListFormat = format; + self.propertyListError = error; + } + + return _responsePropertyList; +} + +- (NSError *)error { + if (_propertyListError) { + return _propertyListError; + } else { + return [super error]; + } +} + +#pragma mark - AFHTTPRequestOperation + ++ (NSSet *)acceptableContentTypes { + return [NSSet setWithObjects:@"application/x-plist", nil]; +} + ++ (BOOL)canProcessRequest:(NSURLRequest *)request { + return [[[request URL] pathExtension] isEqualToString:@"plist"] || [super canProcessRequest:request]; +} + +- (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure +{ + self.completionBlock = ^ { + if ([self isCancelled]) { + return; + } + + if (self.error) { + if (failure) { + dispatch_async(self.failureCallbackQueue ? self.failureCallbackQueue : dispatch_get_main_queue(), ^{ + failure(self, self.error); + }); + } + } else { + dispatch_async(property_list_request_operation_processing_queue(), ^(void) { + id propertyList = self.responsePropertyList; + + if (self.propertyListError) { + if (failure) { + dispatch_async(self.failureCallbackQueue ? self.failureCallbackQueue : dispatch_get_main_queue(), ^{ + failure(self, self.error); + }); + } + } else { + if (success) { + dispatch_async(self.successCallbackQueue ? self.successCallbackQueue : dispatch_get_main_queue(), ^{ + success(self, propertyList); + }); + } + } + }); + } + }; +} + +@end diff --git a/AFNetworking/AFURLConnectionOperation.h b/AFNetworking/AFURLConnectionOperation.h new file mode 100644 index 0000000..0266ced --- /dev/null +++ b/AFNetworking/AFURLConnectionOperation.h @@ -0,0 +1,244 @@ +// AFURLConnectionOperation.h +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import + +/** + Indicates an error occured in AFNetworking. + + @discussion Error codes for AFNetworkingErrorDomain correspond to codes in NSURLErrorDomain. + */ +extern NSString * const AFNetworkingErrorDomain; + +/** + Posted when an operation begins executing. + */ +extern NSString * const AFNetworkingOperationDidStartNotification; + +/** + Posted when an operation finishes. + */ +extern NSString * const AFNetworkingOperationDidFinishNotification; + +/** + `AFURLConnectionOperation` is an `NSOperation` that implements NSURLConnection delegate methods. + + ## Subclassing Notes + + This is the base class of all network request operations. You may wish to create your own subclass in order to implement additional `NSURLConnection` delegate methods (see "`NSURLConnection` Delegate Methods" below), or to provide additional properties and/or class constructors. + + If you are creating a subclass that communicates over the HTTP or HTTPS protocols, you may want to consider subclassing `AFHTTPRequestOperation` instead, as it supports specifying acceptable content types or status codes. + + ## NSURLConnection Delegate Methods + + `AFURLConnectionOperation` implements the following `NSURLConnection` delegate methods: + + - `connection:didReceiveResponse:` + - `connection:didReceiveData:` + - `connectionDidFinishLoading:` + - `connection:didFailWithError:` + - `connection:didSendBodyData:totalBytesWritten:totalBytesExpectedToWrite:` + - `connection:willCacheResponse:` + - `connection:canAuthenticateAgainstProtectionSpace:` + - `connection:didReceiveAuthenticationChallenge:` + + If any of these methods are overriden in a subclass, they _must_ call the `super` implementation first. + + ## Class Constructors + + Class constructors, or methods that return an unowned (zero retain count) instance, are the preferred way for subclasses to encapsulate any particular logic for handling the setup or parsing of response data. For instance, `AFJSONRequestOperation` provides `JSONRequestOperationWithRequest:success:failure:`, which takes block arguments, whose parameter on for a successful request is the JSON object initialized from the `response data`. + + ## Callbacks and Completion Blocks + + The built-in `completionBlock` provided by `NSOperation` allows for custom behavior to be executed after the request finishes. It is a common pattern for class constructors in subclasses to take callback block parameters, and execute them conditionally in the body of its `completionBlock`. Make sure to handle cancelled operations appropriately when setting a `completionBlock` (e.g. returning early before parsing response data). See the implementation of any of the `AFHTTPRequestOperation` subclasses for an example of this. + + @warning Subclasses are strongly discouraged from overriding `setCompletionBlock:`, as `AFURLConnectionOperation`'s implementation includes a workaround to mitigate retain cycles, and what Apple rather ominously refers to as "The Deallocation Problem" (See http://developer.apple.com/library/ios/technotes/tn2109/_index.html#//apple_ref/doc/uid/DTS40010274-CH1-SUBSECTION11) + + @warning Attempting to load a `file://` URL in iOS 4 may result in an `NSInvalidArgumentException`, caused by the connection returning `NSURLResponse` rather than `NSHTTPURLResponse`, which is the behavior as of iOS 5. + */ +@interface AFURLConnectionOperation : NSOperation + +///------------------------------- +/// @name Accessing Run Loop Modes +///------------------------------- + +/** + The run loop modes in which the operation will run on the network thread. By default, this is a single-member set containing `NSRunLoopCommonModes`. + */ +@property (nonatomic, retain) NSSet *runLoopModes; + +///----------------------------------------- +/// @name Getting URL Connection Information +///----------------------------------------- + +/** + The request used by the operation's connection. + */ +@property (readonly, nonatomic, retain) NSURLRequest *request; + +/** + The last response received by the operation's connection. + */ +@property (readonly, nonatomic, retain) NSURLResponse *response; + +/** + The error, if any, that occured in the lifecycle of the request. + */ +@property (readonly, nonatomic, retain) NSError *error; + +///---------------------------- +/// @name Getting Response Data +///---------------------------- + +/** + The data received during the request. + */ +@property (readonly, nonatomic, retain) NSData *responseData; + +/** + The string representation of the response data. + + @discussion This method uses the string encoding of the response, or if UTF-8 if not specified, to construct a string from the response data. + */ +@property (readonly, nonatomic, copy) NSString *responseString; + +///------------------------ +/// @name Accessing Streams +///------------------------ + +/** + The input stream used to read data to be sent during the request. + + @discussion This property acts as a proxy to the `HTTPBodyStream` property of `request`. + */ +@property (nonatomic, retain) NSInputStream *inputStream; + +/** + The output stream that is used to write data received until the request is finished. + + @discussion By default, data is accumulated into a buffer that is stored into `responseData` upon completion of the request. When `outputStream` is set, the data will not be accumulated into an internal buffer, and as a result, the `responseData` property of the completed request will be `nil`. The output stream will be scheduled in the network thread runloop upon being set. + */ +@property (nonatomic, retain) NSOutputStream *outputStream; + +///------------------------------------------------------ +/// @name Initializing an AFURLConnectionOperation Object +///------------------------------------------------------ + +/** + Initializes and returns a newly allocated operation object with a url connection configured with the specified url request. + + @param urlRequest The request object to be used by the operation connection. + + @discussion This is the designated initializer. + */ +- (id)initWithRequest:(NSURLRequest *)urlRequest; + +///---------------------------------- +/// @name Pausing / Resuming Requests +///---------------------------------- + +/** + Pauses the execution of the request operation. + + @discussion A paused operation returns `NO` for `-isReady`, `-isExecuting`, and `-isFinished`. As such, it will remain in an `NSOperationQueue` until it is either cancelled or resumed. Pausing a finished or cancelled operation has no effect. + */ +- (void)pause; + +/** + Whether the request operation is currently paused. + + @return `YES` if the operation is currently paused, otherwise `NO`. + */ +- (BOOL)isPaused; + +/** + Resumes the execution of the paused request operation. + + @discussion Pause/Resume behavior varies depending on the underlying implementation for the operation class. In its base implementation, resuming a paused requests restarts the original request. However, since HTTP defines a specification for how to request a specific content range, `AFHTTPRequestOperation` will resume downloading the request from where it left off, instead of restarting the original request. + */ +- (void)resume; + +///---------------------------------------------- +/// @name Configuring Backgrounding Task Behavior +///---------------------------------------------- + +/** + Specifies that the operation should continue execution after the app has entered the background, and the expiration handler for that background task. + + @param handler A handler to be called shortly before the application’s remaining background time reaches 0. The handler is wrapped in a block that cancels the operation, and cleans up and marks the end of execution, unlike the `handler` parameter in `UIApplication -beginBackgroundTaskWithExpirationHandler:`, which expects this to be done in the handler itself. The handler is called synchronously on the main thread, thus blocking the application’s suspension momentarily while the application is notified. + */ +#if __IPHONE_OS_VERSION_MIN_REQUIRED +- (void)setShouldExecuteAsBackgroundTaskWithExpirationHandler:(void (^)(void))handler; +#endif + +///--------------------------------- +/// @name Setting Progress Callbacks +///--------------------------------- + +/** + Sets a callback to be called when an undetermined number of bytes have been uploaded to the server. + + @param block A block object to be called when an undetermined number of bytes have been uploaded to the server. This block has no return value and takes three arguments: the number of bytes written since the last time the upload progress block was called, the total bytes written, and the total bytes expected to be written during the request, as initially determined by the length of the HTTP body. This block may be called multiple times. + + @see setDownloadProgressBlock + */ +- (void)setUploadProgressBlock:(void (^)(NSInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite))block; + +/** + Sets a callback to be called when an undetermined number of bytes have been downloaded from the server. + + @param block A block object to be called when an undetermined number of bytes have been downloaded from the server. This block has no return value and takes three arguments: the number of bytes read since the last time the download progress block was called, the total bytes read, and the total bytes expected to be read during the request, as initially determined by the expected content size of the `NSHTTPURLResponse` object. This block may be called multiple times. + + @see setUploadProgressBlock + */ +- (void)setDownloadProgressBlock:(void (^)(NSInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead))block; + +///------------------------------------------------- +/// @name Setting NSURLConnection Delegate Callbacks +///------------------------------------------------- + +/** + Sets a block to be executed to determine whether the connection should be able to respond to a protection space's form of authentication, as handled by the `NSURLConnectionDelegate` method `connection:canAuthenticateAgainstProtectionSpace:`. + + @param block A block object to be executed to determine whether the connection should be able to respond to a protection space's form of authentication. The block has a `BOOL` return type and takes two arguments: the URL connection object, and the protection space to authenticate against. + + @discussion If `_AFNETWORKING_ALLOW_INVALID_SSL_CERTIFICATES_` is defined, `connection:canAuthenticateAgainstProtectionSpace:` will accept invalid SSL certificates, returning `YES` if the protection space authentication method is `NSURLAuthenticationMethodServerTrust`. + */ +- (void)setAuthenticationAgainstProtectionSpaceBlock:(BOOL (^)(NSURLConnection *connection, NSURLProtectionSpace *protectionSpace))block; + +/** + Sets a block to be executed when the connection must authenticate a challenge in order to download its request, as handled by the `NSURLConnectionDelegate` method `connection:didReceiveAuthenticationChallenge:`. + + @param block A block object to be executed when the connection must authenticate a challenge in order to download its request. The block has no return type and takes two arguments: the URL connection object, and the challenge that must be authenticated. + + @discussion If `_AFNETWORKING_ALLOW_INVALID_SSL_CERTIFICATES_` is defined, `connection:didReceiveAuthenticationChallenge:` will attempt to have the challenge sender use credentials with invalid SSL certificates. + */ +- (void)setAuthenticationChallengeBlock:(void (^)(NSURLConnection *connection, NSURLAuthenticationChallenge *challenge))block; + +/** + Sets a block to be executed to modify the response a connection will cache, if any, as handled by the `NSURLConnectionDelegate` method `connection:willCacheResponse:`. + + @param block A block object to be executed to determine what response a connection will cache, if any. The block returns an `NSCachedURLResponse` object, the cached response to store in memory or `nil` to prevent the response from being cached, and takes two arguments: the URL connection object, and the cached response provided for the request. + */ +- (void)setCacheResponseBlock:(NSCachedURLResponse * (^)(NSURLConnection *connection, NSCachedURLResponse *cachedResponse))block; + +@end diff --git a/AFNetworking/AFURLConnectionOperation.m b/AFNetworking/AFURLConnectionOperation.m new file mode 100644 index 0000000..ed0d42d --- /dev/null +++ b/AFNetworking/AFURLConnectionOperation.m @@ -0,0 +1,579 @@ +// AFURLConnectionOperation.m +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "AFURLConnectionOperation.h" + +typedef enum { + AFHTTPOperationPausedState = -1, + AFHTTPOperationReadyState = 1, + AFHTTPOperationExecutingState = 2, + AFHTTPOperationFinishedState = 3, +} _AFOperationState; + +typedef signed short AFOperationState; + +#if __IPHONE_OS_VERSION_MIN_REQUIRED +typedef UIBackgroundTaskIdentifier AFBackgroundTaskIdentifier; +#else +typedef id AFBackgroundTaskIdentifier; +#endif + +static NSUInteger const kAFHTTPMinimumInitialDataCapacity = 1024; +static NSUInteger const kAFHTTPMaximumInitialDataCapacity = 1024 * 1024 * 8; + +static NSString * const kAFNetworkingLockName = @"com.alamofire.networking.operation.lock"; + +NSString * const AFNetworkingErrorDomain = @"com.alamofire.networking.error"; + +NSString * const AFNetworkingOperationDidStartNotification = @"com.alamofire.networking.operation.start"; +NSString * const AFNetworkingOperationDidFinishNotification = @"com.alamofire.networking.operation.finish"; + +typedef void (^AFURLConnectionOperationProgressBlock)(NSInteger bytes, long long totalBytes, long long totalBytesExpected); +typedef BOOL (^AFURLConnectionOperationAuthenticationAgainstProtectionSpaceBlock)(NSURLConnection *connection, NSURLProtectionSpace *protectionSpace); +typedef void (^AFURLConnectionOperationAuthenticationChallengeBlock)(NSURLConnection *connection, NSURLAuthenticationChallenge *challenge); +typedef NSCachedURLResponse * (^AFURLConnectionOperationCacheResponseBlock)(NSURLConnection *connection, NSCachedURLResponse *cachedResponse); + +static inline NSString * AFKeyPathFromOperationState(AFOperationState state) { + switch (state) { + case AFHTTPOperationReadyState: + return @"isReady"; + case AFHTTPOperationExecutingState: + return @"isExecuting"; + case AFHTTPOperationFinishedState: + return @"isFinished"; + case AFHTTPOperationPausedState: + return @"isPaused"; + default: + return @"state"; + } +} + +static inline BOOL AFStateTransitionIsValid(AFOperationState fromState, AFOperationState toState, BOOL isCancelled) { + switch (fromState) { + case AFHTTPOperationReadyState: + switch (toState) { + case AFHTTPOperationPausedState: + case AFHTTPOperationExecutingState: + return YES; + case AFHTTPOperationFinishedState: + return isCancelled; + default: + return NO; + } + case AFHTTPOperationExecutingState: + switch (toState) { + case AFHTTPOperationPausedState: + case AFHTTPOperationFinishedState: + return YES; + default: + return NO; + } + case AFHTTPOperationFinishedState: + return NO; + case AFHTTPOperationPausedState: + return toState == AFHTTPOperationReadyState; + default: + return YES; + } +} + +@interface AFURLConnectionOperation () +@property (readwrite, nonatomic, assign) AFOperationState state; +@property (readwrite, nonatomic, assign, getter = isCancelled) BOOL cancelled; +@property (readwrite, nonatomic, retain) NSRecursiveLock *lock; +@property (readwrite, nonatomic, retain) NSURLConnection *connection; +@property (readwrite, nonatomic, retain) NSURLRequest *request; +@property (readwrite, nonatomic, retain) NSURLResponse *response; +@property (readwrite, nonatomic, retain) NSError *error; +@property (readwrite, nonatomic, retain) NSData *responseData; +@property (readwrite, nonatomic, copy) NSString *responseString; +@property (readwrite, nonatomic, assign) long long totalBytesRead; +@property (readwrite, nonatomic, assign) AFBackgroundTaskIdentifier backgroundTaskIdentifier; +@property (readwrite, nonatomic, copy) AFURLConnectionOperationProgressBlock uploadProgress; +@property (readwrite, nonatomic, copy) AFURLConnectionOperationProgressBlock downloadProgress; +@property (readwrite, nonatomic, copy) AFURLConnectionOperationAuthenticationAgainstProtectionSpaceBlock authenticationAgainstProtectionSpace; +@property (readwrite, nonatomic, copy) AFURLConnectionOperationAuthenticationChallengeBlock authenticationChallenge; +@property (readwrite, nonatomic, copy) AFURLConnectionOperationCacheResponseBlock cacheResponse; + +- (void)operationDidStart; +- (void)finish; +@end + +@implementation AFURLConnectionOperation +@synthesize state = _state; +@synthesize cancelled = _cancelled; +@synthesize connection = _connection; +@synthesize runLoopModes = _runLoopModes; +@synthesize request = _request; +@synthesize response = _response; +@synthesize error = _error; +@synthesize responseData = _responseData; +@synthesize responseString = _responseString; +@synthesize totalBytesRead = _totalBytesRead; +@dynamic inputStream; +@synthesize outputStream = _outputStream; +@synthesize backgroundTaskIdentifier = _backgroundTaskIdentifier; +@synthesize uploadProgress = _uploadProgress; +@synthesize downloadProgress = _downloadProgress; +@synthesize authenticationAgainstProtectionSpace = _authenticationAgainstProtectionSpace; +@synthesize authenticationChallenge = _authenticationChallenge; +@synthesize cacheResponse = _cacheResponse; +@synthesize lock = _lock; + ++ (void)networkRequestThreadEntryPoint:(id)__unused object { + do { + NSAutoreleasePool *runLoopPool = [[NSAutoreleasePool alloc] init]; + [[NSRunLoop currentRunLoop] run]; + [runLoopPool drain]; + } while (YES); +} + ++ (NSThread *)networkRequestThread { + static NSThread *_networkRequestThread = nil; + static dispatch_once_t oncePredicate; + + dispatch_once(&oncePredicate, ^{ + _networkRequestThread = [[NSThread alloc] initWithTarget:self selector:@selector(networkRequestThreadEntryPoint:) object:nil]; + [_networkRequestThread start]; + }); + + return _networkRequestThread; +} + +- (id)initWithRequest:(NSURLRequest *)urlRequest { + self = [super init]; + if (!self) { + return nil; + } + + self.lock = [[[NSRecursiveLock alloc] init] autorelease]; + self.lock.name = kAFNetworkingLockName; + + self.runLoopModes = [NSSet setWithObject:NSRunLoopCommonModes]; + + self.request = urlRequest; + + self.outputStream = [NSOutputStream outputStreamToMemory]; + + self.state = AFHTTPOperationReadyState; + + return self; +} + +- (void)dealloc { + [_lock release]; + + [_runLoopModes release]; + + [_request release]; + [_response release]; + [_error release]; + + [_responseData release]; + [_responseString release]; + + if (_outputStream) { + [_outputStream close]; + [_outputStream release]; + _outputStream = nil; + } + +#if __IPHONE_OS_VERSION_MIN_REQUIRED + if (_backgroundTaskIdentifier) { + [[UIApplication sharedApplication] endBackgroundTask:_backgroundTaskIdentifier]; + _backgroundTaskIdentifier = UIBackgroundTaskInvalid; + } +#endif + + [_uploadProgress release]; + [_downloadProgress release]; + [_authenticationChallenge release]; + [_authenticationAgainstProtectionSpace release]; + [_cacheResponse release]; + + [_connection release]; + + [super dealloc]; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%@: %p, state: %@, cancelled: %@ request: %@, response: %@>", NSStringFromClass([self class]), self, AFKeyPathFromOperationState(self.state), ([self isCancelled] ? @"YES" : @"NO"), self.request, self.response]; +} + +- (void)setCompletionBlock:(void (^)(void))block { + [self.lock lock]; + if (!block) { + [super setCompletionBlock:nil]; + } else { + __block id _blockSelf = self; + [super setCompletionBlock:^ { + block(); + [_blockSelf setCompletionBlock:nil]; + }]; + } + [self.lock unlock]; +} + +- (NSInputStream *)inputStream { + return self.request.HTTPBodyStream; +} + +- (void)setInputStream:(NSInputStream *)inputStream { + [self willChangeValueForKey:@"inputStream"]; + NSMutableURLRequest *mutableRequest = [[self.request mutableCopy] autorelease]; + mutableRequest.HTTPBodyStream = inputStream; + self.request = mutableRequest; + [self didChangeValueForKey:@"inputStream"]; +} + +- (void)setOutputStream:(NSOutputStream *)outputStream { + [self willChangeValueForKey:@"outputStream"]; + [outputStream retain]; + + if (_outputStream) { + [_outputStream close]; + [_outputStream release]; + } + _outputStream = outputStream; + [self didChangeValueForKey:@"outputStream"]; + + NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; + for (NSString *runLoopMode in self.runLoopModes) { + [self.outputStream scheduleInRunLoop:runLoop forMode:runLoopMode]; + } +} + +#if __IPHONE_OS_VERSION_MIN_REQUIRED +- (void)setShouldExecuteAsBackgroundTaskWithExpirationHandler:(void (^)(void))handler { + [self.lock lock]; + if (!self.backgroundTaskIdentifier) { + UIApplication *application = [UIApplication sharedApplication]; + self.backgroundTaskIdentifier = [application beginBackgroundTaskWithExpirationHandler:^{ + if (handler) { + handler(); + } + + [self cancel]; + + [application endBackgroundTask:self.backgroundTaskIdentifier]; + self.backgroundTaskIdentifier = UIBackgroundTaskInvalid; + }]; + } + [self.lock unlock]; +} +#endif + +- (void)setUploadProgressBlock:(void (^)(NSInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite))block { + self.uploadProgress = block; +} + +- (void)setDownloadProgressBlock:(void (^)(NSInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead))block { + self.downloadProgress = block; +} + +- (void)setAuthenticationAgainstProtectionSpaceBlock:(BOOL (^)(NSURLConnection *, NSURLProtectionSpace *))block { + self.authenticationAgainstProtectionSpace = block; +} + +- (void)setAuthenticationChallengeBlock:(void (^)(NSURLConnection *connection, NSURLAuthenticationChallenge *challenge))block { + self.authenticationChallenge = block; +} + +- (void)setCacheResponseBlock:(NSCachedURLResponse * (^)(NSURLConnection *connection, NSCachedURLResponse *cachedResponse))block { + self.cacheResponse = block; +} + +- (void)setState:(AFOperationState)state { + [self.lock lock]; + if (AFStateTransitionIsValid(self.state, state, [self isCancelled])) { + NSString *oldStateKey = AFKeyPathFromOperationState(self.state); + NSString *newStateKey = AFKeyPathFromOperationState(state); + + [self willChangeValueForKey:newStateKey]; + [self willChangeValueForKey:oldStateKey]; + _state = state; + [self didChangeValueForKey:oldStateKey]; + [self didChangeValueForKey:newStateKey]; + + switch (state) { + case AFHTTPOperationExecutingState: + [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingOperationDidStartNotification object:self]; + break; + case AFHTTPOperationFinishedState: + [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingOperationDidFinishNotification object:self]; + break; + default: + break; + } + } + [self.lock unlock]; +} + +- (NSString *)responseString { + [self.lock lock]; + if (!_responseString && self.response && self.responseData) { + NSStringEncoding textEncoding = NSUTF8StringEncoding; + if (self.response.textEncodingName) { + textEncoding = CFStringConvertEncodingToNSStringEncoding(CFStringConvertIANACharSetNameToEncoding((CFStringRef)self.response.textEncodingName)); + } + + self.responseString = [[[NSString alloc] initWithData:self.responseData encoding:textEncoding] autorelease]; + } + [self.lock unlock]; + + return _responseString; +} + +- (void)pause { + if ([self isPaused]) { + return; + } + + [self.lock lock]; + self.state = AFHTTPOperationPausedState; + + [self.connection performSelector:@selector(cancel) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]]; + [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingOperationDidFinishNotification object:self]; + [self.lock unlock]; +} + +- (BOOL)isPaused { + return self.state == AFHTTPOperationPausedState; +} + +- (void)resume { + if (![self isPaused]) { + return; + } + + [self.lock lock]; + self.state = AFHTTPOperationReadyState; + + [self start]; + [self.lock unlock]; +} + +#pragma mark - NSOperation + +- (BOOL)isReady { + return self.state == AFHTTPOperationReadyState && [super isReady]; +} + +- (BOOL)isExecuting { + return self.state == AFHTTPOperationExecutingState; +} + +- (BOOL)isFinished { + return self.state == AFHTTPOperationFinishedState; +} + +- (BOOL)isConcurrent { + return YES; +} + +- (void)start { + [self.lock lock]; + if ([self isReady]) { + self.state = AFHTTPOperationExecutingState; + + [self performSelector:@selector(operationDidStart) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]]; + } + [self.lock unlock]; +} + +- (void)operationDidStart { + [self.lock lock]; + if ([self isCancelled]) { + [self finish]; + } else { + self.connection = [[[NSURLConnection alloc] initWithRequest:self.request delegate:self startImmediately:NO] autorelease]; + + NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; + for (NSString *runLoopMode in self.runLoopModes) { + [self.connection scheduleInRunLoop:runLoop forMode:runLoopMode]; + [self.outputStream scheduleInRunLoop:runLoop forMode:runLoopMode]; + } + + [self.connection start]; + } + [self.lock unlock]; +} + +- (void)finish { + self.state = AFHTTPOperationFinishedState; +} + +- (void)cancel { + [self.lock lock]; + if (![self isFinished] && ![self isCancelled]) { + [self willChangeValueForKey:@"isCancelled"]; + _cancelled = YES; + [super cancel]; + [self didChangeValueForKey:@"isCancelled"]; + + // Cancel the connection on the thread it runs on to prevent race conditions + [self performSelector:@selector(cancelConnection) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]]; + } + [self.lock unlock]; +} + +- (void)cancelConnection { + if (self.connection) { + [self.connection cancel]; + + // Manually send this delegate message since `[self.connection cancel]` causes the connection to never send another message to its delegate + NSDictionary *userInfo = nil; + if ([self.request URL]) { + userInfo = [NSDictionary dictionaryWithObject:[self.request URL] forKey:NSURLErrorFailingURLErrorKey]; + } + [self performSelector:@selector(connection:didFailWithError:) withObject:self.connection withObject:[NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorCancelled userInfo:userInfo]]; + } +} + +#pragma mark - NSURLConnectionDelegate + +- (BOOL)connection:(NSURLConnection *)connection +canAuthenticateAgainstProtectionSpace:(NSURLProtectionSpace *)protectionSpace +{ +#ifdef _AFNETWORKING_ALLOW_INVALID_SSL_CERTIFICATES_ + if ([protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { + return YES; + } +#endif + + if (self.authenticationAgainstProtectionSpace) { + return self.authenticationAgainstProtectionSpace(connection, protectionSpace); + } else if ([protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust] || [protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodClientCertificate]) { + return NO; + } else { + return YES; + } +} + +- (void)connection:(NSURLConnection *)connection +didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge +{ +#ifdef _AFNETWORKING_ALLOW_INVALID_SSL_CERTIFICATES_ + if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { + [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge]; + return; + } +#endif + + if (self.authenticationChallenge) { + self.authenticationChallenge(connection, challenge); + } else { + if ([challenge previousFailureCount] == 0) { + NSURLCredential *credential = nil; + + NSString *username = [(NSString *)CFURLCopyUserName((CFURLRef)[self.request URL]) autorelease]; + NSString *password = [(NSString *)CFURLCopyPassword((CFURLRef)[self.request URL]) autorelease]; + + if (username && password) { + credential = [NSURLCredential credentialWithUser:username password:password persistence:NSURLCredentialPersistenceNone]; + } else if (username) { + credential = [[[NSURLCredentialStorage sharedCredentialStorage] credentialsForProtectionSpace:[challenge protectionSpace]] objectForKey:username]; + } else { + credential = [[NSURLCredentialStorage sharedCredentialStorage] defaultCredentialForProtectionSpace:[challenge protectionSpace]]; + } + + if (credential) { + [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge]; + } else { + [[challenge sender] continueWithoutCredentialForAuthenticationChallenge:challenge]; + } + } else { + [[challenge sender] continueWithoutCredentialForAuthenticationChallenge:challenge]; + } + } +} + +- (void)connection:(NSURLConnection *)__unused connection + didSendBodyData:(NSInteger)bytesWritten + totalBytesWritten:(NSInteger)totalBytesWritten +totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite +{ + if (self.uploadProgress) { + self.uploadProgress(bytesWritten, totalBytesWritten, totalBytesExpectedToWrite); + } +} + +- (void)connection:(NSURLConnection *)__unused connection +didReceiveResponse:(NSURLResponse *)response +{ + self.response = response; + + [self.outputStream open]; +} + +- (void)connection:(NSURLConnection *)__unused connection + didReceiveData:(NSData *)data +{ + self.totalBytesRead += [data length]; + + if ([self.outputStream hasSpaceAvailable]) { + const uint8_t *dataBuffer = (uint8_t *) [data bytes]; + [self.outputStream write:&dataBuffer[0] maxLength:[data length]]; + } + + if (self.downloadProgress) { + self.downloadProgress((long long)[data length], self.totalBytesRead, self.response.expectedContentLength); + } +} + +- (void)connectionDidFinishLoading:(NSURLConnection *)__unused connection { + self.responseData = [self.outputStream propertyForKey:NSStreamDataWrittenToMemoryStreamKey]; + + [self.outputStream close]; + + [self finish]; + + self.connection = nil; +} + +- (void)connection:(NSURLConnection *)__unused connection + didFailWithError:(NSError *)error +{ + self.error = error; + + [self.outputStream close]; + + [self finish]; + + self.connection = nil; +} + +- (NSCachedURLResponse *)connection:(NSURLConnection *)connection + willCacheResponse:(NSCachedURLResponse *)cachedResponse +{ + if (self.cacheResponse) { + return self.cacheResponse(connection, cachedResponse); + } else { + if ([self isCancelled]) { + return nil; + } + + return cachedResponse; + } +} + +@end diff --git a/AFNetworking/AFXMLRequestOperation.h b/AFNetworking/AFXMLRequestOperation.h new file mode 100644 index 0000000..0beb677 --- /dev/null +++ b/AFNetworking/AFXMLRequestOperation.h @@ -0,0 +1,89 @@ +// AFXMLRequestOperation.h +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import "AFHTTPRequestOperation.h" + +#import + +/** + `AFXMLRequestOperation` is a subclass of `AFHTTPRequestOperation` for downloading and working with XML response data. + + ## Acceptable Content Types + + By default, `AFXMLRequestOperation` accepts the following MIME types, which includes the official standard, `application/xml`, as well as other commonly-used types: + + - `application/xml` + - `text/xml` + + ## Use With AFHTTPClient + + When `AFXMLRequestOperation` is registered with `AFHTTPClient`, the response object in the success callback of `HTTPRequestOperationWithRequest:success:failure:` will be an instance of `NSXMLParser`. On platforms that support `NSXMLDocument`, you have the option to ignore the response object, and simply use the `responseXMLDocument` property of the operation argument of the callback. + */ +@interface AFXMLRequestOperation : AFHTTPRequestOperation + +///---------------------------- +/// @name Getting Response Data +///---------------------------- + +/** + An `NSXMLParser` object constructed from the response data. + */ +@property (readonly, nonatomic, retain) NSXMLParser *responseXMLParser; + +#if __MAC_OS_X_VERSION_MIN_REQUIRED +/** + An `NSXMLDocument` object constructed from the response data. If an error occurs while parsing, `nil` will be returned, and the `error` property will be set to the error. + */ +@property (readonly, nonatomic, retain) NSXMLDocument *responseXMLDocument; +#endif + +/** + Creates and returns an `AFXMLRequestOperation` object and sets the specified success and failure callbacks. + + @param urlRequest The request object to be loaded asynchronously during execution of the operation + @param success A block object to be executed when the operation finishes successfully. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the XML parser constructed with the response data of request. + @param failure A block object to be executed when the operation finishes unsuccessfully. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the error describing the network error that occurred. + + @return A new XML request operation + */ ++ (AFXMLRequestOperation *)XMLParserRequestOperationWithRequest:(NSURLRequest *)urlRequest + success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSXMLParser *XMLParser))success + failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, NSXMLParser *XMLParse))failure; + + +#if __MAC_OS_X_VERSION_MIN_REQUIRED +/** + Creates and returns an `AFXMLRequestOperation` object and sets the specified success and failure callbacks. + + @param urlRequest The request object to be loaded asynchronously during execution of the operation + @param success A block object to be executed when the operation finishes successfully. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the XML document created from the response data of request. + @param failure A block object to be executed when the operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the resonse data as XML. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the error describing the network or parsing error that occurred. + + @return A new XML request operation + */ ++ (AFXMLRequestOperation *)XMLDocumentRequestOperationWithRequest:(NSURLRequest *)urlRequest + success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSXMLDocument *document))success + failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, NSXMLDocument *document))failure; +#endif + +@end diff --git a/AFNetworking/AFXMLRequestOperation.m b/AFNetworking/AFXMLRequestOperation.m new file mode 100644 index 0000000..f40cacb --- /dev/null +++ b/AFNetworking/AFXMLRequestOperation.m @@ -0,0 +1,177 @@ +// AFXMLRequestOperation.m +// +// Copyright (c) 2011 Gowalla (http://gowalla.com/) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "AFXMLRequestOperation.h" + +#include + +static dispatch_queue_t af_xml_request_operation_processing_queue; +static dispatch_queue_t xml_request_operation_processing_queue() { + if (af_xml_request_operation_processing_queue == NULL) { + af_xml_request_operation_processing_queue = dispatch_queue_create("com.alamofire.networking.xml-request.processing", 0); + } + + return af_xml_request_operation_processing_queue; +} + +@interface AFXMLRequestOperation () +@property (readwrite, nonatomic, retain) NSXMLParser *responseXMLParser; +#if __MAC_OS_X_VERSION_MIN_REQUIRED +@property (readwrite, nonatomic, retain) NSXMLDocument *responseXMLDocument; +#endif +@property (readwrite, nonatomic, retain) NSError *XMLError; +@end + +@implementation AFXMLRequestOperation +@synthesize responseXMLParser = _responseXMLParser; +#if __MAC_OS_X_VERSION_MIN_REQUIRED +@synthesize responseXMLDocument = _responseXMLDocument; +#endif +@synthesize XMLError = _XMLError; + ++ (AFXMLRequestOperation *)XMLParserRequestOperationWithRequest:(NSURLRequest *)urlRequest + success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSXMLParser *XMLParser))success + failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, NSXMLParser *XMLParser))failure +{ + AFXMLRequestOperation *requestOperation = [[[self alloc] initWithRequest:urlRequest] autorelease]; + [requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { + if (success) { + success(operation.request, operation.response, responseObject); + } + } failure:^(AFHTTPRequestOperation *operation, NSError *error) { + if (failure) { + failure(operation.request, operation.response, error, [(AFXMLRequestOperation *)operation responseXMLParser]); + } + }]; + + return requestOperation; +} + +#if __MAC_OS_X_VERSION_MIN_REQUIRED ++ (AFXMLRequestOperation *)XMLDocumentRequestOperationWithRequest:(NSURLRequest *)urlRequest + success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSXMLDocument *document))success + failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, NSXMLDocument *document))failure +{ + AFXMLRequestOperation *requestOperation = [[[self alloc] initWithRequest:urlRequest] autorelease]; + [requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, __unused id responseObject) { + if (success) { + NSXMLDocument *XMLDocument = [(AFXMLRequestOperation *)operation responseXMLDocument]; + success(operation.request, operation.response, XMLDocument); + } + } failure:^(AFHTTPRequestOperation *operation, NSError *error) { + if (failure) { + NSXMLDocument *XMLDocument = [(AFXMLRequestOperation *)operation responseXMLDocument]; + failure(operation.request, operation.response, error, XMLDocument); + } + }]; + + return requestOperation; +} +#endif + +- (void)dealloc { + [_responseXMLParser release]; + +#if __MAC_OS_X_VERSION_MIN_REQUIRED + [_responseXMLDocument release]; +#endif + + [_XMLError release]; + + [super dealloc]; +} + +- (NSXMLParser *)responseXMLParser { + if (!_responseXMLParser && [self.responseData length] > 0 && [self isFinished]) { + self.responseXMLParser = [[[NSXMLParser alloc] initWithData:self.responseData] autorelease]; + } + + return _responseXMLParser; +} + +#if __MAC_OS_X_VERSION_MIN_REQUIRED +- (NSXMLDocument *)responseXMLDocument { + if (!_responseXMLDocument && [self.responseData length] > 0 && [self isFinished]) { + NSError *error = nil; + self.responseXMLDocument = [[[NSXMLDocument alloc] initWithData:self.responseData options:0 error:&error] autorelease]; + self.XMLError = error; + } + + return _responseXMLDocument; +} +#endif + +- (NSError *)error { + if (_XMLError) { + return _XMLError; + } else { + return [super error]; + } +} + +#pragma mark - NSOperation + +- (void)cancel { + [super cancel]; + + self.responseXMLParser.delegate = nil; +} + +#pragma mark - AFHTTPRequestOperation + ++ (NSSet *)acceptableContentTypes { + return [NSSet setWithObjects:@"application/xml", @"text/xml", nil]; +} + ++ (BOOL)canProcessRequest:(NSURLRequest *)request { + return [[[request URL] pathExtension] isEqualToString:@"xml"] || [super canProcessRequest:request]; +} + +- (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success + failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure +{ + self.completionBlock = ^ { + if ([self isCancelled]) { + return; + } + + dispatch_async(xml_request_operation_processing_queue(), ^(void) { + NSXMLParser *XMLParser = self.responseXMLParser; + + if (self.error) { + if (failure) { + dispatch_async(self.failureCallbackQueue ? self.failureCallbackQueue : dispatch_get_main_queue(), ^{ + failure(self, self.error); + }); + } + } else { + if (success) { + dispatch_async(self.successCallbackQueue ? self.successCallbackQueue : dispatch_get_main_queue(), ^{ + success(self, XMLParser); + }); + } + } + }); + }; +} + +@end diff --git a/BitTicker.xcodeproj/project.pbxproj b/BitTicker.xcodeproj/project.pbxproj old mode 100644 new mode 100755 index 0d31b75..6c68bfb --- a/BitTicker.xcodeproj/project.pbxproj +++ b/BitTicker.xcodeproj/project.pbxproj @@ -7,56 +7,52 @@ objects = { /* Begin PBXBuildFile section */ - 83405B28137F68610060CAD4 /* TaggedNSURLConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 83405B22137F68610060CAD4 /* TaggedNSURLConnection.m */; }; - 83405B29137F68610060CAD4 /* NSMutableDictionary+IntegerKeys.m in Sources */ = {isa = PBXBuildFile; fileRef = 83405B24137F68610060CAD4 /* NSMutableDictionary+IntegerKeys.m */; }; - 83405B2A137F68610060CAD4 /* RequestHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 83405B27137F68610060CAD4 /* RequestHandler.m */; }; - 83405B39137F6DDF0060CAD4 /* Trade.m in Sources */ = {isa = PBXBuildFile; fileRef = 83405B31137F6DDF0060CAD4 /* Trade.m */; }; - 83405B3A137F6DDF0060CAD4 /* Ticker.m in Sources */ = {isa = PBXBuildFile; fileRef = 83405B33137F6DDF0060CAD4 /* Ticker.m */; }; - 83405B3B137F6DDF0060CAD4 /* BitcoinMarket.m in Sources */ = {isa = PBXBuildFile; fileRef = 83405B36137F6DDF0060CAD4 /* BitcoinMarket.m */; }; - 83405B3C137F6DDF0060CAD4 /* MtGoxMarket.m in Sources */ = {isa = PBXBuildFile; fileRef = 83405B38137F6DDF0060CAD4 /* MtGoxMarket.m */; }; + 83405B3C137F6DDF0060CAD4 /* MtGox.m in Sources */ = {isa = PBXBuildFile; fileRef = 83405B38137F6DDF0060CAD4 /* MtGox.m */; }; AA239F511379E67300150707 /* StatusItemView.m in Sources */ = {isa = PBXBuildFile; fileRef = AA239F4E1379E67300150707 /* StatusItemView.m */; }; AA239F761379F17200150707 /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AA239F731379F17200150707 /* CoreServices.framework */; }; AA239F771379F17200150707 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = AA239F741379F17200150707 /* libz.dylib */; }; AA239F781379F17200150707 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AA239F751379F17200150707 /* SystemConfiguration.framework */; }; AA239F7B1379F1B200150707 /* Quartz.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AA239F791379F1B200150707 /* Quartz.framework */; }; AA239F7C1379F1B200150707 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AA239F7A1379F1B200150707 /* QuartzCore.framework */; }; + AA435C0E13A2CB550050F307 /* Dropdown.m in Sources */ = {isa = PBXBuildFile; fileRef = AA435C0D13A2CB550050F307 /* Dropdown.m */; }; AA4BBA2D1379E31B005CE351 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AA4BBA2C1379E31B005CE351 /* Cocoa.framework */; }; AA4BBA371379E31C005CE351 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = AA4BBA351379E31C005CE351 /* InfoPlist.strings */; }; AA4BBA3A1379E31C005CE351 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = AA4BBA391379E31C005CE351 /* main.m */; }; AA4BBA401379E31C005CE351 /* BitTickerAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = AA4BBA3F1379E31C005CE351 /* BitTickerAppDelegate.m */; }; AA4BBA431379E31C005CE351 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = AA4BBA411379E31C005CE351 /* MainMenu.xib */; }; - AA6C46CF137E10B2000A1DCB /* NSObject+JSON.m in Sources */ = {isa = PBXBuildFile; fileRef = AA6C46BE137E10B2000A1DCB /* NSObject+JSON.m */; }; - AA6C46D0137E10B2000A1DCB /* SBJsonParser.m in Sources */ = {isa = PBXBuildFile; fileRef = AA6C46C0137E10B2000A1DCB /* SBJsonParser.m */; }; - AA6C46D1137E10B2000A1DCB /* SBJsonStreamParser.m in Sources */ = {isa = PBXBuildFile; fileRef = AA6C46C2137E10B2000A1DCB /* SBJsonStreamParser.m */; }; - AA6C46D2137E10B2000A1DCB /* SBJsonStreamParserAdapter.m in Sources */ = {isa = PBXBuildFile; fileRef = AA6C46C4137E10B2000A1DCB /* SBJsonStreamParserAdapter.m */; }; - AA6C46D3137E10B2000A1DCB /* SBJsonStreamParserState.m in Sources */ = {isa = PBXBuildFile; fileRef = AA6C46C6137E10B2000A1DCB /* SBJsonStreamParserState.m */; }; - AA6C46D4137E10B2000A1DCB /* SBJsonStreamWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = AA6C46C8137E10B2000A1DCB /* SBJsonStreamWriter.m */; }; - AA6C46D5137E10B2000A1DCB /* SBJsonStreamWriterState.m in Sources */ = {isa = PBXBuildFile; fileRef = AA6C46CA137E10B2000A1DCB /* SBJsonStreamWriterState.m */; }; - AA6C46D6137E10B2000A1DCB /* SBJsonTokeniser.m in Sources */ = {isa = PBXBuildFile; fileRef = AA6C46CC137E10B2000A1DCB /* SBJsonTokeniser.m */; }; - AA6C46D7137E10B2000A1DCB /* SBJsonWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = AA6C46CE137E10B2000A1DCB /* SBJsonWriter.m */; }; AA6E6C4D1399DC3E003A4224 /* Credits.html in Resources */ = {isa = PBXBuildFile; fileRef = AA6E6C4C1399DC3E003A4224 /* Credits.html */; }; - AAD172641399BA1E00B505B0 /* EMKeychainItem.m in Sources */ = {isa = PBXBuildFile; fileRef = AAD172631399BA1D00B505B0 /* EMKeychainItem.m */; }; + AA79F0A9152ADB0C002C3EEB /* GraphView.m in Sources */ = {isa = PBXBuildFile; fileRef = AA79F0A7152AD215002C3EEB /* GraphView.m */; }; + AAA32C6915CA3CBB00C45B89 /* CorePlot.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AAA32C6815CA3CBB00C45B89 /* CorePlot.framework */; }; + AAA32C8015CA3D0500C45B89 /* AFHTTPClient.m in Sources */ = {isa = PBXBuildFile; fileRef = AAA32C6C15CA3D0500C45B89 /* AFHTTPClient.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + AAA32C8115CA3D0500C45B89 /* AFHTTPRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = AAA32C6E15CA3D0500C45B89 /* AFHTTPRequestOperation.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + AAA32C8215CA3D0500C45B89 /* AFImageRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = AAA32C7015CA3D0500C45B89 /* AFImageRequestOperation.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + AAA32C8315CA3D0500C45B89 /* AFJSONRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = AAA32C7215CA3D0500C45B89 /* AFJSONRequestOperation.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + AAA32C8415CA3D0500C45B89 /* AFJSONUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = AAA32C7415CA3D0500C45B89 /* AFJSONUtilities.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + AAA32C8515CA3D0500C45B89 /* AFNetworkActivityIndicatorManager.m in Sources */ = {isa = PBXBuildFile; fileRef = AAA32C7615CA3D0500C45B89 /* AFNetworkActivityIndicatorManager.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + AAA32C8615CA3D0500C45B89 /* AFPropertyListRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = AAA32C7915CA3D0500C45B89 /* AFPropertyListRequestOperation.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + AAA32C8715CA3D0500C45B89 /* AFURLConnectionOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = AAA32C7B15CA3D0500C45B89 /* AFURLConnectionOperation.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + AAA32C8815CA3D0500C45B89 /* AFXMLRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = AAA32C7D15CA3D0500C45B89 /* AFXMLRequestOperation.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + AAA32C8A15CA410300C45B89 /* CorePlot.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = AAA32C6815CA3CBB00C45B89 /* CorePlot.framework */; }; AAD1726D1399BD3500B505B0 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AAD1726C1399BD3500B505B0 /* Security.framework */; }; AAD64420137B680E00589EAC /* Logo.icns in Resources */ = {isa = PBXBuildFile; fileRef = AAD6441F137B680E00589EAC /* Logo.icns */; }; /* End PBXBuildFile section */ +/* Begin PBXCopyFilesBuildPhase section */ + AAAB15C113A96DF1006C76FC /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + AAA32C8A15CA410300C45B89 /* CorePlot.framework in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + /* Begin PBXFileReference section */ - 83405B21137F68610060CAD4 /* TaggedNSURLConnection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TaggedNSURLConnection.h; sourceTree = ""; }; - 83405B22137F68610060CAD4 /* TaggedNSURLConnection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TaggedNSURLConnection.m; sourceTree = ""; }; - 83405B23137F68610060CAD4 /* NSMutableDictionary+IntegerKeys.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSMutableDictionary+IntegerKeys.h"; sourceTree = ""; }; - 83405B24137F68610060CAD4 /* NSMutableDictionary+IntegerKeys.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSMutableDictionary+IntegerKeys.m"; sourceTree = ""; }; - 83405B25137F68610060CAD4 /* RequestHandlerDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RequestHandlerDelegate.h; sourceTree = ""; }; - 83405B26137F68610060CAD4 /* RequestHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RequestHandler.h; sourceTree = ""; }; - 83405B27137F68610060CAD4 /* RequestHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RequestHandler.m; sourceTree = ""; }; - 83405B30137F6DDF0060CAD4 /* Trade.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Trade.h; sourceTree = ""; }; - 83405B31137F6DDF0060CAD4 /* Trade.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Trade.m; sourceTree = ""; }; - 83405B32137F6DDF0060CAD4 /* Ticker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Ticker.h; sourceTree = ""; }; - 83405B33137F6DDF0060CAD4 /* Ticker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Ticker.m; sourceTree = ""; }; - 83405B34137F6DDF0060CAD4 /* BitcoinMarketDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BitcoinMarketDelegate.h; sourceTree = ""; }; - 83405B35137F6DDF0060CAD4 /* BitcoinMarket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BitcoinMarket.h; sourceTree = ""; }; - 83405B36137F6DDF0060CAD4 /* BitcoinMarket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BitcoinMarket.m; sourceTree = ""; }; - 83405B37137F6DDF0060CAD4 /* MtGoxMarket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MtGoxMarket.h; sourceTree = ""; }; - 83405B38137F6DDF0060CAD4 /* MtGoxMarket.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MtGoxMarket.m; sourceTree = ""; }; + 83405B37137F6DDF0060CAD4 /* MtGox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MtGox.h; sourceTree = ""; }; + 83405B38137F6DDF0060CAD4 /* MtGox.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MtGox.m; sourceTree = ""; }; AA239F4D1379E67300150707 /* StatusItemView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StatusItemView.h; sourceTree = ""; }; AA239F4E1379E67300150707 /* StatusItemView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = StatusItemView.m; sourceTree = ""; }; AA239F731379F17200150707 /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = System/Library/Frameworks/CoreServices.framework; sourceTree = SDKROOT; }; @@ -64,6 +60,8 @@ AA239F751379F17200150707 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; AA239F791379F1B200150707 /* Quartz.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Quartz.framework; path = System/Library/Frameworks/Quartz.framework; sourceTree = SDKROOT; }; AA239F7A1379F1B200150707 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; + AA435C0C13A2CB550050F307 /* Dropdown.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Dropdown.h; sourceTree = ""; }; + AA435C0D13A2CB550050F307 /* Dropdown.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Dropdown.m; sourceTree = ""; }; AA4BBA281379E31B005CE351 /* BitTicker.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = BitTicker.app; sourceTree = BUILT_PRODUCTS_DIR; }; AA4BBA2C1379E31B005CE351 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; AA4BBA2F1379E31B005CE351 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; @@ -76,28 +74,30 @@ AA4BBA3E1379E31C005CE351 /* BitTickerAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BitTickerAppDelegate.h; sourceTree = ""; }; AA4BBA3F1379E31C005CE351 /* BitTickerAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BitTickerAppDelegate.m; sourceTree = ""; }; AA4BBA421379E31C005CE351 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MainMenu.xib; sourceTree = ""; }; - AA6C46BC137E10B2000A1DCB /* JSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSON.h; sourceTree = ""; }; - AA6C46BD137E10B2000A1DCB /* NSObject+JSON.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSObject+JSON.h"; sourceTree = ""; }; - AA6C46BE137E10B2000A1DCB /* NSObject+JSON.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSObject+JSON.m"; sourceTree = ""; }; - AA6C46BF137E10B2000A1DCB /* SBJsonParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonParser.h; sourceTree = ""; }; - AA6C46C0137E10B2000A1DCB /* SBJsonParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonParser.m; sourceTree = ""; }; - AA6C46C1137E10B2000A1DCB /* SBJsonStreamParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonStreamParser.h; sourceTree = ""; }; - AA6C46C2137E10B2000A1DCB /* SBJsonStreamParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonStreamParser.m; sourceTree = ""; }; - AA6C46C3137E10B2000A1DCB /* SBJsonStreamParserAdapter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonStreamParserAdapter.h; sourceTree = ""; }; - AA6C46C4137E10B2000A1DCB /* SBJsonStreamParserAdapter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonStreamParserAdapter.m; sourceTree = ""; }; - AA6C46C5137E10B2000A1DCB /* SBJsonStreamParserState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonStreamParserState.h; sourceTree = ""; }; - AA6C46C6137E10B2000A1DCB /* SBJsonStreamParserState.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonStreamParserState.m; sourceTree = ""; }; - AA6C46C7137E10B2000A1DCB /* SBJsonStreamWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonStreamWriter.h; sourceTree = ""; }; - AA6C46C8137E10B2000A1DCB /* SBJsonStreamWriter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonStreamWriter.m; sourceTree = ""; }; - AA6C46C9137E10B2000A1DCB /* SBJsonStreamWriterState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonStreamWriterState.h; sourceTree = ""; }; - AA6C46CA137E10B2000A1DCB /* SBJsonStreamWriterState.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonStreamWriterState.m; sourceTree = ""; }; - AA6C46CB137E10B2000A1DCB /* SBJsonTokeniser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonTokeniser.h; sourceTree = ""; }; - AA6C46CC137E10B2000A1DCB /* SBJsonTokeniser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonTokeniser.m; sourceTree = ""; }; - AA6C46CD137E10B2000A1DCB /* SBJsonWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SBJsonWriter.h; sourceTree = ""; }; - AA6C46CE137E10B2000A1DCB /* SBJsonWriter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SBJsonWriter.m; sourceTree = ""; }; AA6E6C4C1399DC3E003A4224 /* Credits.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = Credits.html; sourceTree = ""; }; - AAD172621399BA1D00B505B0 /* EMKeychainItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EMKeychainItem.h; sourceTree = ""; }; - AAD172631399BA1D00B505B0 /* EMKeychainItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EMKeychainItem.m; sourceTree = ""; }; + AA79F0A6152AD215002C3EEB /* GraphView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GraphView.h; sourceTree = ""; }; + AA79F0A7152AD215002C3EEB /* GraphView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GraphView.m; sourceTree = ""; }; + AA79F0A8152AD664002C3EEB /* BitTicker.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = BitTicker.entitlements; sourceTree = ""; }; + AAA32C6815CA3CBB00C45B89 /* CorePlot.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = CorePlot.framework; sourceTree = ""; }; + AAA32C6B15CA3D0500C45B89 /* AFHTTPClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AFHTTPClient.h; sourceTree = ""; }; + AAA32C6C15CA3D0500C45B89 /* AFHTTPClient.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AFHTTPClient.m; sourceTree = ""; }; + AAA32C6D15CA3D0500C45B89 /* AFHTTPRequestOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AFHTTPRequestOperation.h; sourceTree = ""; }; + AAA32C6E15CA3D0500C45B89 /* AFHTTPRequestOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AFHTTPRequestOperation.m; sourceTree = ""; }; + AAA32C6F15CA3D0500C45B89 /* AFImageRequestOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AFImageRequestOperation.h; sourceTree = ""; }; + AAA32C7015CA3D0500C45B89 /* AFImageRequestOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AFImageRequestOperation.m; sourceTree = ""; }; + AAA32C7115CA3D0500C45B89 /* AFJSONRequestOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AFJSONRequestOperation.h; sourceTree = ""; }; + AAA32C7215CA3D0500C45B89 /* AFJSONRequestOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AFJSONRequestOperation.m; sourceTree = ""; }; + AAA32C7315CA3D0500C45B89 /* AFJSONUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AFJSONUtilities.h; sourceTree = ""; }; + AAA32C7415CA3D0500C45B89 /* AFJSONUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AFJSONUtilities.m; sourceTree = ""; }; + AAA32C7515CA3D0500C45B89 /* AFNetworkActivityIndicatorManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AFNetworkActivityIndicatorManager.h; sourceTree = ""; }; + AAA32C7615CA3D0500C45B89 /* AFNetworkActivityIndicatorManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AFNetworkActivityIndicatorManager.m; sourceTree = ""; }; + AAA32C7715CA3D0500C45B89 /* AFNetworking.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AFNetworking.h; sourceTree = ""; }; + AAA32C7815CA3D0500C45B89 /* AFPropertyListRequestOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AFPropertyListRequestOperation.h; sourceTree = ""; }; + AAA32C7915CA3D0500C45B89 /* AFPropertyListRequestOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AFPropertyListRequestOperation.m; sourceTree = ""; }; + AAA32C7A15CA3D0500C45B89 /* AFURLConnectionOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AFURLConnectionOperation.h; sourceTree = ""; }; + AAA32C7B15CA3D0500C45B89 /* AFURLConnectionOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AFURLConnectionOperation.m; sourceTree = ""; }; + AAA32C7C15CA3D0500C45B89 /* AFXMLRequestOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AFXMLRequestOperation.h; sourceTree = ""; }; + AAA32C7D15CA3D0500C45B89 /* AFXMLRequestOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AFXMLRequestOperation.m; sourceTree = ""; }; AAD1726C1399BD3500B505B0 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; AAD6441F137B680E00589EAC /* Logo.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = Logo.icns; sourceTree = ""; }; /* End PBXFileReference section */ @@ -114,73 +114,19 @@ AA239F771379F17200150707 /* libz.dylib in Frameworks */, AA239F781379F17200150707 /* SystemConfiguration.framework in Frameworks */, AA4BBA2D1379E31B005CE351 /* Cocoa.framework in Frameworks */, + AAA32C6915CA3CBB00C45B89 /* CorePlot.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 83405B0D137F5D8A0060CAD4 /* JSON */ = { - isa = PBXGroup; - children = ( - AA6C46BC137E10B2000A1DCB /* JSON.h */, - AA6C46BD137E10B2000A1DCB /* NSObject+JSON.h */, - AA6C46BE137E10B2000A1DCB /* NSObject+JSON.m */, - AA6C46BF137E10B2000A1DCB /* SBJsonParser.h */, - AA6C46C0137E10B2000A1DCB /* SBJsonParser.m */, - AA6C46C1137E10B2000A1DCB /* SBJsonStreamParser.h */, - AA6C46C2137E10B2000A1DCB /* SBJsonStreamParser.m */, - AA6C46C3137E10B2000A1DCB /* SBJsonStreamParserAdapter.h */, - AA6C46C4137E10B2000A1DCB /* SBJsonStreamParserAdapter.m */, - AA6C46C5137E10B2000A1DCB /* SBJsonStreamParserState.h */, - AA6C46C6137E10B2000A1DCB /* SBJsonStreamParserState.m */, - AA6C46C7137E10B2000A1DCB /* SBJsonStreamWriter.h */, - AA6C46C8137E10B2000A1DCB /* SBJsonStreamWriter.m */, - AA6C46C9137E10B2000A1DCB /* SBJsonStreamWriterState.h */, - AA6C46CA137E10B2000A1DCB /* SBJsonStreamWriterState.m */, - AA6C46CB137E10B2000A1DCB /* SBJsonTokeniser.h */, - AA6C46CC137E10B2000A1DCB /* SBJsonTokeniser.m */, - AA6C46CD137E10B2000A1DCB /* SBJsonWriter.h */, - AA6C46CE137E10B2000A1DCB /* SBJsonWriter.m */, - ); - name = JSON; - sourceTree = ""; - }; - 83405B20137F684E0060CAD4 /* Networking */ = { - isa = PBXGroup; - children = ( - 83405B25137F68610060CAD4 /* RequestHandlerDelegate.h */, - 83405B26137F68610060CAD4 /* RequestHandler.h */, - 83405B27137F68610060CAD4 /* RequestHandler.m */, - ); - name = Networking; - sourceTree = ""; - }; - 83405B2B137F68870060CAD4 /* Additions */ = { + 837DF12E139B2EC8009987F3 /* Nibs */ = { isa = PBXGroup; children = ( - 83405B21137F68610060CAD4 /* TaggedNSURLConnection.h */, - 83405B22137F68610060CAD4 /* TaggedNSURLConnection.m */, - 83405B23137F68610060CAD4 /* NSMutableDictionary+IntegerKeys.h */, - 83405B24137F68610060CAD4 /* NSMutableDictionary+IntegerKeys.m */, - ); - name = Additions; - sourceTree = ""; - }; - 83405B2F137F6CFE0060CAD4 /* Models */ = { - isa = PBXGroup; - children = ( - 83405B30137F6DDF0060CAD4 /* Trade.h */, - 83405B31137F6DDF0060CAD4 /* Trade.m */, - 83405B32137F6DDF0060CAD4 /* Ticker.h */, - 83405B33137F6DDF0060CAD4 /* Ticker.m */, - 83405B34137F6DDF0060CAD4 /* BitcoinMarketDelegate.h */, - 83405B35137F6DDF0060CAD4 /* BitcoinMarket.h */, - 83405B36137F6DDF0060CAD4 /* BitcoinMarket.m */, - 83405B37137F6DDF0060CAD4 /* MtGoxMarket.h */, - 83405B38137F6DDF0060CAD4 /* MtGoxMarket.m */, + AA4BBA411379E31C005CE351 /* MainMenu.xib */, ); - name = Models; + name = Nibs; sourceTree = ""; }; AA4BBA1D1379E31B005CE351 = { @@ -203,8 +149,8 @@ AA4BBA2B1379E31B005CE351 /* Frameworks */ = { isa = PBXGroup; children = ( - AAD1726C1399BD3500B505B0 /* Security.framework */, - AA4BBA2C1379E31B005CE351 /* Cocoa.framework */, + AAA32C6A15CA3D0500C45B89 /* AFNetworking */, + AAA32C6815CA3CBB00C45B89 /* CorePlot.framework */, AA4BBA2E1379E31B005CE351 /* Other Frameworks */, ); name = Frameworks; @@ -213,6 +159,8 @@ AA4BBA2E1379E31B005CE351 /* Other Frameworks */ = { isa = PBXGroup; children = ( + AA4BBA2C1379E31B005CE351 /* Cocoa.framework */, + AAD1726C1399BD3500B505B0 /* Security.framework */, AA239F791379F1B200150707 /* Quartz.framework */, AA239F7A1379F1B200150707 /* QuartzCore.framework */, AA239F741379F17200150707 /* libz.dylib */, @@ -228,17 +176,18 @@ AA4BBA321379E31B005CE351 /* BitTicker */ = { isa = PBXGroup; children = ( - AAD172621399BA1D00B505B0 /* EMKeychainItem.h */, - AAD172631399BA1D00B505B0 /* EMKeychainItem.m */, - 83405B2F137F6CFE0060CAD4 /* Models */, - 83405B2B137F68870060CAD4 /* Additions */, - 83405B20137F684E0060CAD4 /* Networking */, - 83405B0D137F5D8A0060CAD4 /* JSON */, + AA79F0A8152AD664002C3EEB /* BitTicker.entitlements */, + 83405B37137F6DDF0060CAD4 /* MtGox.h */, + 83405B38137F6DDF0060CAD4 /* MtGox.m */, AA239F4D1379E67300150707 /* StatusItemView.h */, AA239F4E1379E67300150707 /* StatusItemView.m */, + AA435C0C13A2CB550050F307 /* Dropdown.h */, + AA435C0D13A2CB550050F307 /* Dropdown.m */, + AA79F0A6152AD215002C3EEB /* GraphView.h */, + AA79F0A7152AD215002C3EEB /* GraphView.m */, AA4BBA3E1379E31C005CE351 /* BitTickerAppDelegate.h */, AA4BBA3F1379E31C005CE351 /* BitTickerAppDelegate.m */, - AA4BBA411379E31C005CE351 /* MainMenu.xib */, + 837DF12E139B2EC8009987F3 /* Nibs */, AA4BBA331379E31B005CE351 /* Supporting Files */, ); path = BitTicker; @@ -257,6 +206,32 @@ name = "Supporting Files"; sourceTree = ""; }; + AAA32C6A15CA3D0500C45B89 /* AFNetworking */ = { + isa = PBXGroup; + children = ( + AAA32C6B15CA3D0500C45B89 /* AFHTTPClient.h */, + AAA32C6C15CA3D0500C45B89 /* AFHTTPClient.m */, + AAA32C6D15CA3D0500C45B89 /* AFHTTPRequestOperation.h */, + AAA32C6E15CA3D0500C45B89 /* AFHTTPRequestOperation.m */, + AAA32C6F15CA3D0500C45B89 /* AFImageRequestOperation.h */, + AAA32C7015CA3D0500C45B89 /* AFImageRequestOperation.m */, + AAA32C7115CA3D0500C45B89 /* AFJSONRequestOperation.h */, + AAA32C7215CA3D0500C45B89 /* AFJSONRequestOperation.m */, + AAA32C7315CA3D0500C45B89 /* AFJSONUtilities.h */, + AAA32C7415CA3D0500C45B89 /* AFJSONUtilities.m */, + AAA32C7515CA3D0500C45B89 /* AFNetworkActivityIndicatorManager.h */, + AAA32C7615CA3D0500C45B89 /* AFNetworkActivityIndicatorManager.m */, + AAA32C7715CA3D0500C45B89 /* AFNetworking.h */, + AAA32C7815CA3D0500C45B89 /* AFPropertyListRequestOperation.h */, + AAA32C7915CA3D0500C45B89 /* AFPropertyListRequestOperation.m */, + AAA32C7A15CA3D0500C45B89 /* AFURLConnectionOperation.h */, + AAA32C7B15CA3D0500C45B89 /* AFURLConnectionOperation.m */, + AAA32C7C15CA3D0500C45B89 /* AFXMLRequestOperation.h */, + AAA32C7D15CA3D0500C45B89 /* AFXMLRequestOperation.m */, + ); + path = AFNetworking; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -267,6 +242,7 @@ AA4BBA241379E31B005CE351 /* Sources */, AA4BBA251379E31B005CE351 /* Frameworks */, AA4BBA261379E31B005CE351 /* Resources */, + AAAB15C113A96DF1006C76FC /* CopyFiles */, ); buildRules = ( ); @@ -283,6 +259,7 @@ AA4BBA1F1379E31B005CE351 /* Project object */ = { isa = PBXProject; attributes = { + LastUpgradeCheck = 0430; ORGANIZATIONNAME = none; }; buildConfigurationList = AA4BBA221379E31B005CE351 /* Build configuration list for PBXProject "BitTicker" */; @@ -321,26 +298,21 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + AA79F0A9152ADB0C002C3EEB /* GraphView.m in Sources */, AA4BBA3A1379E31C005CE351 /* main.m in Sources */, AA4BBA401379E31C005CE351 /* BitTickerAppDelegate.m in Sources */, AA239F511379E67300150707 /* StatusItemView.m in Sources */, - AA6C46CF137E10B2000A1DCB /* NSObject+JSON.m in Sources */, - AA6C46D0137E10B2000A1DCB /* SBJsonParser.m in Sources */, - AA6C46D1137E10B2000A1DCB /* SBJsonStreamParser.m in Sources */, - AA6C46D2137E10B2000A1DCB /* SBJsonStreamParserAdapter.m in Sources */, - AA6C46D3137E10B2000A1DCB /* SBJsonStreamParserState.m in Sources */, - AA6C46D4137E10B2000A1DCB /* SBJsonStreamWriter.m in Sources */, - AA6C46D5137E10B2000A1DCB /* SBJsonStreamWriterState.m in Sources */, - AA6C46D6137E10B2000A1DCB /* SBJsonTokeniser.m in Sources */, - AA6C46D7137E10B2000A1DCB /* SBJsonWriter.m in Sources */, - 83405B28137F68610060CAD4 /* TaggedNSURLConnection.m in Sources */, - 83405B29137F68610060CAD4 /* NSMutableDictionary+IntegerKeys.m in Sources */, - 83405B2A137F68610060CAD4 /* RequestHandler.m in Sources */, - 83405B39137F6DDF0060CAD4 /* Trade.m in Sources */, - 83405B3A137F6DDF0060CAD4 /* Ticker.m in Sources */, - 83405B3B137F6DDF0060CAD4 /* BitcoinMarket.m in Sources */, - 83405B3C137F6DDF0060CAD4 /* MtGoxMarket.m in Sources */, - AAD172641399BA1E00B505B0 /* EMKeychainItem.m in Sources */, + 83405B3C137F6DDF0060CAD4 /* MtGox.m in Sources */, + AA435C0E13A2CB550050F307 /* Dropdown.m in Sources */, + AAA32C8015CA3D0500C45B89 /* AFHTTPClient.m in Sources */, + AAA32C8115CA3D0500C45B89 /* AFHTTPRequestOperation.m in Sources */, + AAA32C8215CA3D0500C45B89 /* AFImageRequestOperation.m in Sources */, + AAA32C8315CA3D0500C45B89 /* AFJSONRequestOperation.m in Sources */, + AAA32C8415CA3D0500C45B89 /* AFJSONUtilities.m in Sources */, + AAA32C8515CA3D0500C45B89 /* AFNetworkActivityIndicatorManager.m in Sources */, + AAA32C8615CA3D0500C45B89 /* AFPropertyListRequestOperation.m in Sources */, + AAA32C8715CA3D0500C45B89 /* AFURLConnectionOperation.m in Sources */, + AAA32C8815CA3D0500C45B89 /* AFXMLRequestOperation.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -402,12 +374,22 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + CLANG_ENABLE_OBJC_ARC = YES; + CODE_SIGN_ENTITLEMENTS = BitTicker/BitTicker.entitlements; COPY_PHASE_STRIP = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "\"$(SRCROOT)\"", + "\"$(SRCROOT)/../../Libraries/CorePlot_1.0/Binaries/MacOS\"", + ); GCC_DYNAMIC_NO_PIC = NO; GCC_ENABLE_OBJC_EXCEPTIONS = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "BitTicker/BitTicker-Prefix.pch"; + HEADER_SEARCH_PATHS = "\"$(SRCROOT)/../../Libraries/CorePlot_1.0/Binaries/MacOS/CorePlot.framework/Headers/\""; INFOPLIST_FILE = "BitTicker/BitTicker-Info.plist"; + MACOSX_DEPLOYMENT_TARGET = 10.6.8; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; }; @@ -417,12 +399,22 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD_64_BIT)"; + CLANG_ENABLE_OBJC_ARC = YES; + CODE_SIGN_ENTITLEMENTS = BitTicker/BitTicker.entitlements; COPY_PHASE_STRIP = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "\"$(SRCROOT)\"", + "\"$(SRCROOT)/../../Libraries/CorePlot_1.0/Binaries/MacOS\"", + ); GCC_ENABLE_OBJC_EXCEPTIONS = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "BitTicker/BitTicker-Prefix.pch"; + HEADER_SEARCH_PATHS = "\"$(SRCROOT)/../../Libraries/CorePlot_1.0/Binaries/MacOS/CorePlot.framework/Headers/\""; INFOPLIST_FILE = "BitTicker/BitTicker-Info.plist"; + MACOSX_DEPLOYMENT_TARGET = 10.6.8; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; }; diff --git a/BitTicker/BitTicker-Info.plist b/BitTicker/BitTicker-Info.plist old mode 100644 new mode 100755 index 35bdb14..2fbc7de --- a/BitTicker/BitTicker-Info.plist +++ b/BitTicker/BitTicker-Info.plist @@ -2,6 +2,8 @@ + + CFBundleDevelopmentRegion en CFBundleExecutable @@ -9,7 +11,7 @@ CFBundleIconFile Logo.icns CFBundleIdentifier - com.xercespartners.${PRODUCT_NAME:rfc1034identifier} + com.infincia.${PRODUCT_NAME:rfc1034identifier} CFBundleInfoDictionaryVersion 6.0 CFBundleName @@ -22,15 +24,17 @@ ???? CFBundleVersion 1 + LSApplicationCategoryType + public.app-category.utilities LSMinimumSystemVersion ${MACOSX_DEPLOYMENT_TARGET} LSUIElement - + + NSHumanReadableCopyright + Copyright 2012 Stephen Oliver <mrsteveman1@gmail.com> NSMainNibFile MainMenu NSPrincipalClass NSApplication - NSHumanReadableCopyright - Copyright 2011 Stephen Oliver <mrsteveman1@gmail.com> diff --git a/BitTicker/BitTicker-Prefix.pch b/BitTicker/BitTicker-Prefix.pch old mode 100644 new mode 100755 index c6b0b38..0cf6435 --- a/BitTicker/BitTicker-Prefix.pch +++ b/BitTicker/BitTicker-Prefix.pch @@ -1,37 +1,10 @@ /* - BitTicker is Copyright 2011 Stephen Oliver - http://github.com/mrsteveman1 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + BitTicker is Copyright 2012 Stephen Oliver + http://github.com/infincia + + */ #ifdef __OBJC__ #import -#endif - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Debug -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -#define DEBUG_ON // Toggle to DEBUG_OFF or comment out to hide all debug code - -#ifdef DEBUG_ON -#define MSLog(format, ...) CFShow([[NSString stringWithFormat:@"<%@:%d> ",[[NSString stringWithUTF8String:__FILE__] lastPathComponent],__LINE__] stringByAppendingFormat:format, ## __VA_ARGS__]) -#else -#define MSlog(format, ...) -#endif - -#define MSLogRect(rect) MSLog(@"%s x:%.4f, y:%.4f, w:%.4f, h%.4f", #rect, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height) -#define MSLogSize(size) MSLog(@"%s w:%.4f, h:%.4f", #size, size.width, size.height) -#define MSLogPoint(point) MSLog(@"%s x:%.4f, y:%.4f", #point, point.x, point.y) \ No newline at end of file +#endif \ No newline at end of file diff --git a/BitTicker/BitTicker.entitlements b/BitTicker/BitTicker.entitlements new file mode 100644 index 0000000..bc04cfb --- /dev/null +++ b/BitTicker/BitTicker.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.network.client + + + diff --git a/BitTicker/BitTickerAppDelegate.h b/BitTicker/BitTickerAppDelegate.h old mode 100644 new mode 100755 index cec0fef..7e176e8 --- a/BitTicker/BitTickerAppDelegate.h +++ b/BitTicker/BitTickerAppDelegate.h @@ -1,89 +1,19 @@ /* - BitTicker is Copyright 2011 Stephen Oliver - http://github.com/mrsteveman1 + BitTicker is Copyright 2012 Stephen Oliver + http://github.com/infincia - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ +*/ #import -@class Ticker; -@class StatusItemView; -@class RequestHandler; +@class MtGox; -@class MtGoxMarket; -#import "BitcoinMarketDelegate.h" -@interface BitTickerAppDelegate : NSObject { - MtGoxMarket *market; - - NSTimer *tickerTimer; - NSTimer *walletTimer; - - NSMutableArray *stats; - StatusItemView *statusItemView; - NSStatusItem *_statusItem; - //fields for each stat - NSTextField *highValue; - NSTextField *lowValue; - NSTextField *volValue; - NSTextField *buyValue; - NSTextField *sellValue; - NSTextField *lastValue; - NSTextField *spreadValue; - - NSView *statsView; - NSMenuItem *statsItem; - - NSView *technicalsView; - NSMenuItem *technicalsItem; - - // below the line - NSMenuItem *quitItem; - NSMenuItem *aboutItem; - NSMenuItem *settingsItem; - NSMenuItem *refreshItem; - NSMenuItem *preferenceItem; +@interface BitTickerAppDelegate : NSObject { + MtGox *mtgox; - NSMenu *trayMenu; - - NSNumberFormatter *currencyFormatter; - - //Settings - NSString *username; - NSString *password; - NSString *selected_market; - - //User interface stuff - IBOutlet NSWindow *settings_window; - IBOutlet NSTextField *username_field; - IBOutlet NSSecureTextField *password_field; - IBOutlet NSComboBox *market_selector; } -- (void) quitProgram:(id)sender; -- (void)refreshTicker:(id)sender; -- (IBAction)showSettings:(id)sender; -- (IBAction)showAbout:(id)sender; -@property (retain) NSString *username; -@property (retain) NSString *password; -@property (retain) NSString *selected_market; -@property (retain, nonatomic) NSNumber *tickerValue; -@property (retain) NSMutableArray *stats; -@property (nonatomic) NSInteger cancelThread; - @end diff --git a/BitTicker/BitTickerAppDelegate.m b/BitTicker/BitTickerAppDelegate.m old mode 100644 new mode 100755 index d9888fb..c2e6494 --- a/BitTicker/BitTickerAppDelegate.m +++ b/BitTicker/BitTickerAppDelegate.m @@ -1,383 +1,19 @@ /* - BitTicker is Copyright 2011 Stephen Oliver - http://github.com/mrsteveman1 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + BitTicker is Copyright 2012 Stephen Oliver + http://github.com/infincia + + */ #import "BitTickerAppDelegate.h" -#import "Ticker.h" -#import "StatusItemView.h" -#import "EMKeychainItem.h" -#import "MtGoxMarket.h" - +#import "MtGox.h" @implementation BitTickerAppDelegate -@synthesize stats; -@synthesize cancelThread; -@synthesize tickerValue; -@dynamic username,password,selected_market; - -- (void)awakeFromNib { - _statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength]; - [_statusItem retain]; - - statusItemView = [[StatusItemView alloc] init]; - statusItemView.statusItem = _statusItem; - [statusItemView setToolTip:NSLocalizedString(@"BitTicker", - @"Status Item Tooltip")]; - [_statusItem setView:statusItemView]; - - // menu stuff - trayMenu = [[NSMenu alloc] initWithTitle:@"Ticker"]; - //graphItem = [[NSMenuItem alloc] init]; - statsItem = [[NSMenuItem alloc] init]; - statsView = [[NSView alloc] initWithFrame:CGRectMake(0,70,180,90)]; - [statsItem setView:statsView]; - [trayMenu addItem:statsItem]; - - NSString *menuFont = @"LucidaGrande"; - NSInteger menuFontSize = 12; - NSInteger menuHeight = 15; - NSInteger labelWidth = 70; - NSInteger valueWidth = 60; - - NSInteger labelOffset = 20; - NSInteger valueOffset = 110; - highValue = [[NSTextField alloc] initWithFrame:CGRectMake(valueOffset,75,valueWidth,menuHeight)]; - [highValue setEditable:FALSE]; - [highValue setBordered:NO]; - [highValue setAlignment:NSRightTextAlignment]; - [highValue setBackgroundColor:[NSColor clearColor]]; - [highValue setTextColor:[NSColor blackColor]]; - [highValue setFont:[NSFont fontWithName:menuFont size:menuFontSize]]; - [statsView addSubview:highValue]; - - NSTextField *highLabel = [[NSTextField alloc] initWithFrame:CGRectMake(labelOffset,75,labelWidth,menuHeight)]; - [highLabel setEditable:FALSE]; - [highLabel setBordered:NO]; - [highLabel setAlignment:NSLeftTextAlignment]; - [highLabel setBackgroundColor:[NSColor clearColor]]; - [highLabel setStringValue:@"High:"]; - [highLabel setTextColor:[NSColor blackColor]]; - [highLabel setFont:[NSFont fontWithName:menuFont size:menuFontSize]]; - [statsView addSubview:highLabel]; - [highLabel release]; - - // - lowValue = [[NSTextField alloc] initWithFrame:CGRectMake(valueOffset,60,valueWidth,menuHeight)]; - [lowValue setEditable:FALSE]; - [lowValue setBordered:NO]; - [lowValue setAlignment:NSRightTextAlignment]; - [lowValue setBackgroundColor:[NSColor clearColor]]; - [lowValue setTextColor:[NSColor blackColor]]; - [lowValue setFont:[NSFont fontWithName:menuFont size:menuFontSize]]; - [statsView addSubview:lowValue]; - - NSTextField *lowLabel = [[NSTextField alloc] initWithFrame:CGRectMake(labelOffset,60,labelWidth,menuHeight)]; - [lowLabel setEditable:FALSE]; - [lowLabel setBordered:NO]; - [lowLabel setAlignment:NSLeftTextAlignment]; - [lowLabel setBackgroundColor:[NSColor clearColor]]; - [lowLabel setStringValue:@"Low:"]; - [lowLabel setTextColor:[NSColor blackColor]]; - [lowLabel setFont:[NSFont fontWithName:menuFont size:menuFontSize]]; - [statsView addSubview:lowLabel]; - [lowLabel release]; - - // - buyValue = [[NSTextField alloc] initWithFrame:CGRectMake(valueOffset,45,valueWidth,menuHeight)]; - [buyValue setEditable:FALSE]; - [buyValue setBordered:NO]; - [buyValue setAlignment:NSRightTextAlignment]; - [buyValue setBackgroundColor:[NSColor clearColor]]; - [buyValue setTextColor:[NSColor blackColor]]; - [buyValue setFont:[NSFont fontWithName:menuFont size:menuFontSize]]; - [statsView addSubview:buyValue]; - - NSTextField *buyLabel = [[NSTextField alloc] initWithFrame:CGRectMake(labelOffset,45,labelWidth,menuHeight)]; - [buyLabel setEditable:FALSE]; - [buyLabel setBordered:NO]; - [buyLabel setAlignment:NSLeftTextAlignment]; - [buyLabel setBackgroundColor:[NSColor clearColor]]; - [buyLabel setStringValue:@"Buy:"]; - [buyLabel setTextColor:[NSColor blackColor]]; - [buyLabel setFont:[NSFont fontWithName:menuFont size:menuFontSize]]; - [statsView addSubview:buyLabel]; - [buyLabel release]; - - // - sellValue = [[NSTextField alloc] initWithFrame:CGRectMake(valueOffset,30,valueWidth,menuHeight)]; - [sellValue setEditable:FALSE]; - [sellValue setBordered:NO]; - [sellValue setAlignment:NSRightTextAlignment]; - [sellValue setBackgroundColor:[NSColor clearColor]]; - [sellValue setTextColor:[NSColor blackColor]]; - [sellValue setFont:[NSFont fontWithName:menuFont size:menuFontSize]]; - [statsView addSubview:sellValue]; - - NSTextField *sellLabel = [[NSTextField alloc] initWithFrame:CGRectMake(labelOffset,30,labelWidth,menuHeight)]; - [sellLabel setEditable:FALSE]; - [sellLabel setBordered:NO]; - [sellLabel setAlignment:NSLeftTextAlignment]; - [sellLabel setBackgroundColor:[NSColor clearColor]]; - [sellLabel setStringValue:@"Sell:"]; - [sellLabel setTextColor:[NSColor blackColor]]; - [sellLabel setFont:[NSFont fontWithName:menuFont size:menuFontSize]]; - [statsView addSubview:sellLabel]; - [sellLabel release]; - - // - lastValue = [[NSTextField alloc] initWithFrame:CGRectMake(valueOffset,15,valueWidth,menuHeight)]; - [lastValue setEditable:FALSE]; - [lastValue setBordered:NO]; - [lastValue setAlignment:NSRightTextAlignment]; - [lastValue setBackgroundColor:[NSColor clearColor]]; - [lastValue setTextColor:[NSColor blackColor]]; - [lastValue setFont:[NSFont fontWithName:menuFont size:menuFontSize]]; - [statsView addSubview:lastValue]; - - NSTextField *lastLabel = [[NSTextField alloc] initWithFrame:CGRectMake(labelOffset,15,labelWidth,menuHeight)]; - [lastLabel setEditable:FALSE]; - [lastLabel setBordered:NO]; - [lastLabel setAlignment:NSLeftTextAlignment]; - [lastLabel setBackgroundColor:[NSColor clearColor]]; - [lastLabel setStringValue:@"Last:"]; - [lastLabel setTextColor:[NSColor blackColor]]; - [lastLabel setFont:[NSFont fontWithName:menuFont size:menuFontSize]]; - [statsView addSubview:lastLabel]; - [lastLabel release]; - - // - volValue = [[NSTextField alloc] initWithFrame:CGRectMake(valueOffset,0,valueWidth,menuHeight)]; - [volValue setEditable:FALSE]; - [volValue setBordered:NO]; - [volValue setAlignment:NSRightTextAlignment]; - [volValue setBackgroundColor:[NSColor clearColor]]; - [volValue setTextColor:[NSColor blackColor]]; - [volValue setFont:[NSFont fontWithName:menuFont size:menuFontSize]]; - [statsView addSubview:volValue]; - - - NSTextField *volLabel = [[NSTextField alloc] initWithFrame:CGRectMake(labelOffset,0,labelWidth,menuHeight)]; - [volLabel setEditable:FALSE]; - [volLabel setBordered:NO]; - [volLabel setAlignment:NSLeftTextAlignment]; - [volLabel setBackgroundColor:[NSColor clearColor]]; - [volLabel setStringValue:@"Volume:"]; - [volLabel setTextColor:[NSColor blackColor]]; - [volLabel setFont:[NSFont fontWithName:menuFont size:menuFontSize]]; - [statsView addSubview:volLabel]; - [volLabel release]; - - - [trayMenu addItem:[NSMenuItem separatorItem]]; - - technicalsItem = [[NSMenuItem alloc] init]; - technicalsView = [[NSView alloc] initWithFrame:CGRectMake(0,0,180,13)]; - [technicalsItem setView:technicalsView]; - [trayMenu addItem:technicalsItem]; - - spreadValue = [[NSTextField alloc] initWithFrame:CGRectMake(valueOffset, 0, valueWidth, menuHeight)]; - [spreadValue setEditable:FALSE]; - [spreadValue setBordered:NO]; - [spreadValue setAlignment:NSRightTextAlignment]; - [spreadValue setBackgroundColor:[NSColor clearColor]]; - [spreadValue setTextColor:[NSColor blackColor]]; - [spreadValue setFont:[NSFont fontWithName:menuFont size:menuFontSize]]; - [technicalsView addSubview:spreadValue]; - - NSTextField *spreadLabel = [[NSTextField alloc] initWithFrame:CGRectMake(labelOffset,0,labelWidth,menuHeight)]; - [spreadLabel setEditable:FALSE]; - [spreadLabel setBordered:NO]; - [spreadLabel setAlignment:NSLeftTextAlignment]; - [spreadLabel setBackgroundColor:[NSColor clearColor]]; - [spreadLabel setStringValue:@"Spread:"]; - [spreadLabel setTextColor:[NSColor blackColor]]; - [spreadLabel setFont:[NSFont fontWithName:menuFont size:menuFontSize]]; - [technicalsView addSubview:spreadLabel]; - [spreadLabel release]; - - [trayMenu addItem:[NSMenuItem separatorItem]]; - - - refreshItem = [trayMenu addItemWithTitle:@"Refresh" - action:@selector(refreshTicker:) - keyEquivalent:@"r"]; - aboutItem = [trayMenu addItemWithTitle: @"About" - action: @selector (showAbout:) - keyEquivalent: @"a"]; - settingsItem = [trayMenu addItemWithTitle: @"Settings" - action: @selector (showSettings:) - keyEquivalent: @"s"]; - - - quitItem = [trayMenu addItemWithTitle: @"Quit" - action: @selector (quitProgram:) - keyEquivalent: @"q"]; - - - [statusItemView setMenu:trayMenu]; - - - currencyFormatter = [[NSNumberFormatter alloc] init]; - currencyFormatter.numberStyle = NSNumberFormatterCurrencyStyle; - currencyFormatter.currencyCode = @"USD"; // TODO: Base on market currency - currencyFormatter.thousandSeparator = @","; // TODO: Base on local seperator for currency - currencyFormatter.alwaysShowsDecimalSeparator = YES; - currencyFormatter.hasThousandSeparators = YES; - currencyFormatter.minimumFractionDigits = 4; // TODO: Configurable - - - if ([[NSUserDefaults standardUserDefaults] boolForKey:@"AlreadyRan"]) { - - } else { - [[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:@"AlreadyRan"]; - [[NSUserDefaults standardUserDefaults] setObject:@"ChangeMe" forKey:@"username"]; - [[NSUserDefaults standardUserDefaults] setObject:@"MtGox" forKey:@"selected_market"]; - [[NSUserDefaults standardUserDefaults] synchronize]; - if (!self.password) { - self.password = @"ChangeMe"; - } - } - MSLog(@"Starting"); - market = [[MtGoxMarket alloc] initWithDelegate:self]; - - tickerTimer = [[NSTimer scheduledTimerWithTimeInterval:30 target:market selector:@selector(fetchTicker) userInfo:nil repeats:YES] retain]; - //walletTimer = [[NSTimer scheduledTimerWithTimeInterval:30 target:market selector:@selector(fetchWallet) userInfo:nil repeats:YES] retain]; - - [market fetchTicker]; - //[market fetchWallet]; -} - -#pragma mark Application delegate - -- (void)applicationWillTerminate:(NSNotification *)notification { - [market release]; - [tickerTimer invalidate]; - [tickerTimer release]; - [_statusItem release]; - [statusItemView release]; - [trayMenu release]; - [statsItem release]; - [currencyFormatter release]; - - [highValue release]; - [lowValue release]; - [volValue release]; - [buyValue release]; - [sellValue release]; - [lastValue release]; - [spreadValue release]; - - [technicalsItem release]; - [technicalsView release]; - -} - -- (IBAction)showAbout:(id)sender { - [NSApp orderFrontStandardAboutPanel:nil]; - [NSApp activateIgnoringOtherApps:YES]; -} - -- (IBAction)showSettings:(id)sender { - [settings_window makeKeyAndOrderFront:nil]; - [NSApp activateIgnoringOtherApps:YES]; -} - -- (NSString *)username { - return [[NSUserDefaults standardUserDefaults] objectForKey:@"username"]; -} - -- (void)setUsername:(NSString *)newusername { - [[NSUserDefaults standardUserDefaults] setObject:newusername forKey:@"username"]; - [[NSUserDefaults standardUserDefaults] synchronize]; - NSLog(@"Set Username: %@",newusername); -} - -- (NSString *)password { - EMGenericKeychainItem *keychainItem = [EMGenericKeychainItem genericKeychainItemForService:@"BitTicker-MtGox" withUsername:self.username]; - return keychainItem.password; -} - -- (void)setPassword:(NSString *)newpassword { - EMGenericKeychainItem *keychainItem = [EMGenericKeychainItem genericKeychainItemForService:@"BitTicker-MtGox" withUsername:self.username]; - keychainItem.password = newpassword; - NSLog(@"Set password: %@",newpassword); -} - -- (NSString *)selected_market { - return [[NSUserDefaults standardUserDefaults] objectForKey:@"selected_market"]; -} - -- (void)setSelected_market:(NSString *)newmarket { - [[NSUserDefaults standardUserDefaults] setObject:newmarket forKey:@"selected_market"]; - [[NSUserDefaults standardUserDefaults] synchronize]; - NSLog(@"Set Market: %@",newmarket); -} - - -#pragma mark Actions -- (void)quitProgram:(id)sender { - [NSApp terminate:self]; -} -- (void)refreshTicker:(id)sender { - [market fetchTicker]; -} -#pragma mark Bitcoin market delegate -// A request failed for some reason, for example the API being down --(void)bitcoinMarket:(BitcoinMarket*)market requestFailedWithError:(NSError*)error { - MSLog(@"Error: %@",error); -} - -// Request wasn't formatted as expected --(void)bitcoinMarket:(BitcoinMarket*)market didReceiveInvalidResponse:(NSData*)data { - MSLog(@"Invalid response: %@",data); -} - --(void)bitcoinMarket:(BitcoinMarket*)market didReceiveTicker:(Ticker*)ticker { - [statusItemView setTickerValue:ticker.last]; - MSLog(@"Got mah ticker: %@",ticker); - - [highValue setStringValue:[currencyFormatter stringFromNumber:ticker.high]]; - [lowValue setStringValue:[currencyFormatter stringFromNumber:ticker.low]]; - [buyValue setStringValue:[currencyFormatter stringFromNumber:ticker.buy]]; - [sellValue setStringValue: [currencyFormatter stringFromNumber:ticker.sell]]; - [lastValue setStringValue: [currencyFormatter stringFromNumber:ticker.last]]; - - NSNumberFormatter *volumeFormatter = [[NSNumberFormatter alloc] init]; - volumeFormatter.numberStyle = NSNumberFormatterDecimalStyle; - volumeFormatter.hasThousandSeparators = YES; - [volValue setStringValue:[volumeFormatter stringFromNumber:ticker.volume]]; - - [volumeFormatter release]; - - double ask = [ticker.sell doubleValue]; - double bid = [ticker.buy doubleValue]; - NSNumber *spread = [NSNumber numberWithDouble:ask-bid]; - [spreadValue setStringValue:[currencyFormatter stringFromNumber:spread]]; -} - --(void)bitcoinMarket:(BitcoinMarket*)market didReceiveRecentTradesData:(NSArray*)trades { - -} - --(void)bitcoinMarket:(BitcoinMarket*)market didReceiveWallet:(NSDictionary*)wallet { +- (void)awakeFromNib { + mtgox = [[MtGox alloc] init]; } @end diff --git a/BitTicker/BitcoinMarket.h b/BitTicker/BitcoinMarket.h deleted file mode 100644 index 8cb90cc..0000000 --- a/BitTicker/BitcoinMarket.h +++ /dev/null @@ -1,38 +0,0 @@ -// -// BitcoinMarket.h -// Bitcoin Trader -// -// Created by Matt Stith on 4/27/11. -// Copyright 2011 Insomnia Addict. All rights reserved. -// - -#import - -#import "BitcoinMarketDelegate.h" -#import "RequestHandlerDelegate.h" - -@class RequestHandler; - -@interface BitcoinMarket : NSObject { - RequestHandler *requestHandler; - id _delegate; - - NSMutableDictionary *_selectorMap; -} --(id)initWithDelegate:(id)delegate; - --(void)downloadJsonDataFromURL:(NSURL*)url callback:(SEL)callback; --(void)downloadJsonDataFromURL:(NSURL*)url withPostData:(NSDictionary*)postData callback:(SEL)callback; - -// Overwrite these in each market --(NSURL*)getTickerDataURL; --(NSURL*)getRecentTradeURL; - --(void)fetchRecentTrades; --(void)fetchTicker; --(void)fetchMarketDepth; --(void)fetchWallet; - -@property (nonatomic, assign) id delegate; - -@end diff --git a/BitTicker/BitcoinMarket.m b/BitTicker/BitcoinMarket.m deleted file mode 100644 index 2045dee..0000000 --- a/BitTicker/BitcoinMarket.m +++ /dev/null @@ -1,129 +0,0 @@ -// -// BitcoinMarket.m -// Bitcoin Trader -// -// Created by Matt Stith on 4/27/11. -// Copyright 2011 Insomnia Addict. All rights reserved. -// - -#import "BitcoinMarket.h" - -#import "RequestHandler.h" - -#import "JSON.h" - -@implementation BitcoinMarket - -@synthesize delegate=_delegate; - --(id)initWithDelegate:(id)delegate { - if (!(self = [super init])) return self; - - requestHandler = [[RequestHandler alloc] initWithDelegate:self]; - self.delegate = delegate; - - _selectorMap = [[NSMutableDictionary alloc] init]; - - return self; -} - --(void)dealloc { - [requestHandler release]; - [_selectorMap release]; - [super dealloc]; -} - -#pragma mark - Market request methods - -#pragma mark - Downloading methods --(void)downloadJsonDataFromURL:(NSURL*)url callback:(SEL)callback { - [self downloadJsonDataFromURL:url withPostData:nil callback:callback]; -} --(void)downloadJsonDataFromURL:(NSURL *)url withPostData:(NSDictionary*)postData callback:(SEL)callback { - NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url]; - - NSMutableString *body = [NSMutableString string]; - - if (postData) { - [urlRequest setHTTPMethod:@"POST"]; - BOOL appendAmpersand = NO; - for(NSString *key in postData) { - NSString *value = [postData objectForKey:key]; - [body appendFormat:@"%@=%@%@",key,value,appendAmpersand?@"&":@""]; - if (!appendAmpersand) appendAmpersand = YES; - } - } else { - [urlRequest setHTTPMethod:@"GET"]; - } - - [urlRequest setHTTPBody:[body dataUsingEncoding:NSUTF8StringEncoding]]; - - NSInteger newTag = [requestHandler startConnection:urlRequest]; - - NSMethodSignature *signature = [self methodSignatureForSelector:callback]; - NSInvocation *invoke = [NSInvocation invocationWithMethodSignature:signature]; - [invoke setTarget:self]; - [invoke setSelector:callback]; - - [_selectorMap setObject:invoke forIntegerKey:newTag]; - -} - -#pragma mark - MultiConnectionHandlerDelegate methods --(void)request:(NSInteger)tag didFinishWithData:(NSData*)data { - // TODO: Don't assume a JSON response - SBJsonParser *jsonParser = [SBJsonParser new]; - NSString *jsonString = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]; - jsonString = [jsonString stringByTrimmingCharactersInSet:[NSCharacterSet controlCharacterSet]]; - //MSLog(@"About to parse string: %@",jsonString); - - - NSInvocation *invocation = [_selectorMap objectForIntegerKey:tag]; - - [invocation setTarget:self]; - - - NSError *error = nil; - id results = [jsonParser objectWithString:jsonString error:&error]; - - if (error) { - MSLog(@"ERROR from connection %i: %@",tag,error); - id delegate = invocation.target; - [delegate bitcoinMarket:self requestFailedWithError:error]; - MSLog(@"Raw data: %@",data); - } else { - [invocation setArgument:&results atIndex:2]; - [invocation invoke]; - } - - [jsonParser release]; - - [_selectorMap removeObjectForInteger:tag]; -} - --(void)request:(NSInteger)tag didFailWithError:(NSError*)error { - -} - -#pragma mark - Methods for subclasses to overwrite --(NSURL*)getTickerDataURL { - [NSException raise:@"MethodNotOverwrittenException" format:@"%s must be overwritten by BitcoinMarket subclasses",__func__]; - return nil; -} --(NSURL*)getRecentTradeURL { - [NSException raise:@"MethodNotOverwrittenException" format:@"%s must be overwritten by BitcoinMarket subclasses",__func__]; - return nil; -} --(void)fetchRecentTrades { - [NSException raise:@"MethodNotOverwrittenException" format:@"%s must be overwritten by BitcoinMarket subclasses",__func__]; -} --(void)fetchTicker { - [NSException raise:@"MethodNotOverwrittenException" format:@"%s must be overwritten by BitcoinMarket subclasses",__func__]; -} --(void)fetchMarketDepth { - [NSException raise:@"MethodNotOverwrittenException" format:@"%s must be overwritten by BitcoinMarket subclasses",__func__]; -} --(void)fetchWallet { - [NSException raise:@"MethodNotOverwrittenException" format:@"%s must be overwritten by BitcoinMarket subclasses",__func__]; -} -@end diff --git a/BitTicker/BitcoinMarketDelegate.h b/BitTicker/BitcoinMarketDelegate.h deleted file mode 100644 index 3bd0fd7..0000000 --- a/BitTicker/BitcoinMarketDelegate.h +++ /dev/null @@ -1,29 +0,0 @@ -// -// BitcoinMarketDataSource.h -// Bitcoin Trader -// -// Created by Matt Stith on 4/27/11. -// Copyright 2011 Insomnia Addict. All rights reserved. -// - -#import - -@class BitcoinMarket; -@class Ticker; - -@protocol BitcoinMarketDelegate - -@required - -// A request failed for some reason, for example the API being down --(void)bitcoinMarket:(BitcoinMarket*)market requestFailedWithError:(NSError*)error; - -// Request wasn't formatted as expected --(void)bitcoinMarket:(BitcoinMarket*)market didReceiveInvalidResponse:(NSData*)data; - -@optional - --(void)bitcoinMarket:(BitcoinMarket*)market didReceiveTicker:(Ticker*)ticker; --(void)bitcoinMarket:(BitcoinMarket*)market didReceiveRecentTradesData:(NSArray*)trades; --(void)bitcoinMarket:(BitcoinMarket*)market didReceiveWallet:(NSDictionary*)wallet; -@end diff --git a/BitTicker/Credits.html b/BitTicker/Credits.html old mode 100644 new mode 100755 index d2917da..89db608 --- a/BitTicker/Credits.html +++ b/BitTicker/Credits.html @@ -8,7 +8,7 @@

1EW4tmzG3Xwa7LPmebhrHhAuZWmPe6UKrk

-Source on Github +Source on Github \ No newline at end of file diff --git a/BitTicker/Dropdown.h b/BitTicker/Dropdown.h new file mode 100755 index 0000000..bc4b0a5 --- /dev/null +++ b/BitTicker/Dropdown.h @@ -0,0 +1,39 @@ +/* + BitTicker is Copyright 2012 Stephen Oliver + http://github.com/infincia + +*/ + +#import + + +@class StatusItemView; + +@interface Dropdown : NSObject { + NSMenu *trayMenu; + + NSMutableDictionary *_viewDict; + StatusItemView *statusItemView; + NSStatusItem *_statusItem; + + NSNumberFormatter *currencyFormatter; + NSNumberFormatter *volumeFormatter; + + NSNumber *_tickerValue; + + + +} + +@property (copy) NSNumber *tickerValue; + +@property (strong) NSString *high; +@property (strong) NSString *low; +@property (strong) NSString *vol; +@property (strong) NSString *buy; +@property (strong) NSString *sell; +@property (strong) NSString *last; + +@property (strong) IBOutlet NSView *dropdownView; + +@end diff --git a/BitTicker/Dropdown.m b/BitTicker/Dropdown.m new file mode 100755 index 0000000..805d3ea --- /dev/null +++ b/BitTicker/Dropdown.m @@ -0,0 +1,80 @@ +/* + BitTicker is Copyright 2012 Stephen Oliver + http://github.com/infincia + +*/ + +#import "Dropdown.h" +#import "StatusItemView.h" + +@implementation Dropdown + +@synthesize tickerValue = _tickerValue; + + + +@synthesize high; +@synthesize low; +@synthesize vol; +@synthesize buy; +@synthesize sell; +@synthesize last; +@synthesize dropdownView; + + + +- (id)init +{ + self = [super init]; + + volumeFormatter = [[NSNumberFormatter alloc] init]; + volumeFormatter.numberStyle = NSNumberFormatterDecimalStyle; + volumeFormatter.hasThousandSeparators = YES; + + currencyFormatter = [[NSNumberFormatter alloc] init]; + currencyFormatter.numberStyle = NSNumberFormatterCurrencyStyle; + currencyFormatter.currencyCode = @"USD"; // TODO: Base on market currency + currencyFormatter.thousandSeparator = @","; // TODO: Base on local seperator for currency + currencyFormatter.alwaysShowsDecimalSeparator = YES; + currencyFormatter.hasThousandSeparators = YES; + currencyFormatter.minimumFractionDigits = 4; // TODO: Configurable + return self; +} + +-(void)awakeFromNib { + NSLog(@"Awake from nib in dropdown"); + _statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength]; + + statusItemView = [[StatusItemView alloc] init]; + statusItemView.statusItem = _statusItem; + [statusItemView setToolTip:@"BitTicker"]; + + [_statusItem setView:statusItemView]; + + trayMenu = [[NSMenu alloc] initWithTitle:@"Ticker"]; + [statusItemView setMenu:trayMenu]; + NSMenuItem *menuItem = [[NSMenuItem alloc] init]; + [menuItem setView:self.dropdownView]; + [trayMenu addItem:menuItem]; + + + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveTicker:) name:@"MtGox-Ticker" object:nil]; + +} + +-(void)didReceiveTicker:(NSNotification *)notification { + NSAssert([NSThread currentThread] == [NSThread mainThread],@"Not unning on main thread!"); + NSLog(@"Dropdown got ticker"); + NSDictionary *ticker = [[notification object] objectForKey:@"ticker"]; + + self.high = [currencyFormatter stringFromNumber:[ticker objectForKey:@"high"]]; + self.low = [currencyFormatter stringFromNumber:[ticker objectForKey:@"low"]]; + self.buy = [currencyFormatter stringFromNumber:[ticker objectForKey:@"buy"]]; + self.sell = [currencyFormatter stringFromNumber:[ticker objectForKey:@"sell"]]; + self.last = [currencyFormatter stringFromNumber:[ticker objectForKey:@"last"]]; + self.vol = [volumeFormatter stringFromNumber:[ticker objectForKey:@"vol"]]; + +} + +@end diff --git a/BitTicker/EMKeychainItem.h b/BitTicker/EMKeychainItem.h deleted file mode 100644 index b1df285..0000000 --- a/BitTicker/EMKeychainItem.h +++ /dev/null @@ -1,175 +0,0 @@ -/*Copyright (c) 2009 Extendmac, LLC. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation - files (the "Software"), to deal in the Software without - restriction, including without limitation the rights to use, - copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following - conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. - */ - -//Last Updated February 8th, 2011. - - -#import -#import -#import - -/*! - @abstract EMKeychainItem is a self-contained wrapper class for two-way communication with the keychain. You can add, retrieve, and remove both generic and internet keychain items. - @dicussion All keychain items have a username, password, and optionally a label. - */ -@interface EMKeychainItem : NSObject -{ - @private - NSString *mUsername; - NSString *mPassword; - NSString *mLabel; - - @protected - SecKeychainItemRef mCoreKeychainItem; -} - -/*! - @abstract Returns whether or not errors are logged. - @discussion Errors occur whenever a keychain item fails to appropriately update a property, or when a given keychain item cannot be found. - */ -+ (BOOL)logsErrors; - -//! @abstracts Sets whether or not errors are logged. -+ (void)setLogsErrors:(BOOL)logsErrors; - -//! @abstracts Locks the keychain. -+ (void)lockKeychain; - -//! @abstract Unlocks the keychain. -+ (void)unlockKeychain; - -//! @abstract The keychain item's username. -@property (readwrite, copy) NSString *username; - -//! @abstract The keychain item's password. -@property (readwrite, copy) NSString *password; - -//! @abstract The keychain item's label. -@property (readwrite, copy) NSString *label; - -/*! - @abstract Removes the receiver from the keychain. - @discussion After calling this method, you should generally discard of the receiver. The receiver cannot be "re-added" to the keychain; invoke either addGenericKeychainItemForService:... or addInternetKeychainItemForServer:... instead. - */ -- (void)removeFromKeychain; - -@end - -#pragma mark - - -/*! - @abstract An EMGenericKeychainItem wraps the functionality and data-members associated with a generic keychain item. - @discussion Generic keychain items have a service name in addition to the standard keychain item properties. - */ -@interface EMGenericKeychainItem : EMKeychainItem -{ - @private - NSString *mServiceName; -} - -//! @abstract The keychain item's service name. -@property (readwrite, copy) NSString *serviceName; - -/*! - @abstract Returns, if possible, a generic keychain item that corresponds to the given service. - @param serviceName The service name. Cannot be nil. - @param username The username. Cannot be nil. - @result An EMGenericKeychainItem if the keychain item can be discovered. Otherwise, nil. - */ -+ (EMGenericKeychainItem *)genericKeychainItemForService:(NSString *)serviceName - withUsername:(NSString *)username; - -/*! - @abstract Adds a keychain item for the given service. - @param serviceName The service name. Cannot be nil. - @param username The username. Cannot be nil. - @param password The password to associate with the username and service. Cannot be nil. - @result An EMGenericKeychainItem if the service can be added to the keychain. Otherwise, nil. - */ -+ (EMGenericKeychainItem *)addGenericKeychainItemForService:(NSString *)serviceName - withUsername:(NSString *)username - password:(NSString *)password; -@end - -#pragma mark - - -/*! - @abstract An EMInternetKeychainItem wraps the functionality and data-members associated with an internet keychain item. - @discussion Internet keychain items can optionally have a server, path, port, and protocol in addition to the standard keychain item properties. - */ -@interface EMInternetKeychainItem : EMKeychainItem -{ - @private - NSString *mServer; - NSString *mPath; - NSInteger mPort; - SecProtocolType mProtocol; -} - - -/*! - @abstract Returns, if possible, an internet keychain item that corresponds to the given server. - @param server The server. Cannot be nil. - @param username The username. Cannot be nil. - @param path The path. - @param port The port. - @param protocol The protocol. - @result An EMInternetKeychainItem if the keychain item can be discovered. Otherwise, nil. - */ -+ (EMInternetKeychainItem *)internetKeychainItemForServer:(NSString *)server - withUsername:(NSString *)username - path:(NSString *)path - port:(NSInteger)port - protocol:(SecProtocolType)protocol; - -/*! - @abstract Adds a keychain item for the given server. - @param server The server. Cannot be nil. - @param username The username. Cannot be nil. - @param password The password to associate with the server, username, path, port, and protocol. Cannot be nil. - @param path The path. - @param port The port. - @param protocol The protocol. - @result An EMInternetKeychainItem if the item can be added to the keychain. Otherwise, nil. - */ -+ (EMInternetKeychainItem *)addInternetKeychainItemForServer:(NSString *)server - withUsername:(NSString *)username - password:(NSString *)password - path:(NSString *)path - port:(NSInteger)port - protocol:(SecProtocolType)protocol; - -//! @abstract The keychain item's server. -@property (readwrite, copy) NSString *server; - -//! @abstract The keychain item's path. -@property (readwrite, copy) NSString *path; - -//! @abstract The keychain item's port. -@property (readwrite, assign) NSInteger port; - -//! @abstract The keychain item's protocol. -@property (readwrite, assign) SecProtocolType protocol; - -@end \ No newline at end of file diff --git a/BitTicker/EMKeychainItem.m b/BitTicker/EMKeychainItem.m deleted file mode 100644 index 6795066..0000000 --- a/BitTicker/EMKeychainItem.m +++ /dev/null @@ -1,540 +0,0 @@ -/*Copyright (c) 2009 Extendmac, LLC. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation - files (the "Software"), to deal in the Software without - restriction, including without limitation the rights to use, - copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following - conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - OTHER DEALINGS IN THE SOFTWARE. - */ - -#import "EMKeychainItem.h" - -@interface EMKeychainItem (Private) - -/*! - @abstract Modifies the given attribute to be newValue. - @param attributeTag The attribute's tag. - @param newValue A pointer to the new value. - @param newLength The length of the new value. -*/ -- (void)_modifyAttributeWithTag:(SecItemAttr)attributeTag toBeValue:(void *)newValue ofLength:(UInt32)newLength; - -@end - -@implementation EMKeychainItem - -static BOOL _logsErrors; - -+ (void)lockKeychain -{ - SecKeychainLock(NULL); -} - -+ (void)unlockKeychain -{ - SecKeychainUnlock(NULL, 0, NULL, NO); -} - -+ (BOOL)logsErrors -{ - @synchronized (self) - { - return _logsErrors; - } - return NO; -} - -+ (void)setLogsErrors:(BOOL)logsErrors -{ - @synchronized (self) - { - if (_logsErrors == logsErrors) - return; - - _logsErrors = logsErrors; - } -} - -#pragma mark - - -- (id)_initWithCoreKeychainItem:(SecKeychainItemRef)item - username:(NSString *)username - password:(NSString *)password -{ - if ((self = [super init])) - { - mCoreKeychainItem = item; - mUsername = [username copy]; - mPassword = [password copy]; - - return self; - } - return nil; -} - -- (void)_modifyAttributeWithTag:(SecItemAttr)attributeTag toBeValue:(void *)newValue ofLength:(UInt32)newLength -{ - NSAssert(mCoreKeychainItem, @"Core keychain item is nil. You cannot modify a keychain item that is not in the keychain."); - - SecKeychainAttribute attributes[1]; - attributes[0].tag = attributeTag; - attributes[0].length = newLength; - attributes[0].data = newValue; - - SecKeychainAttributeList attributeList; - attributeList.count = 1; - attributeList.attr = attributes; - - SecKeychainItemModifyAttributesAndData(mCoreKeychainItem, &attributeList, 0, NULL); -} - -- (void)dealloc -{ - [mUsername release]; - [mPassword release]; - [mLabel release]; - - if (mCoreKeychainItem) - CFRelease(mCoreKeychainItem); - - [super dealloc]; -} - -#pragma mark - -#pragma mark General Properties -@dynamic password; -- (NSString *)password -{ - @synchronized (self) - { - return [[mPassword copy] autorelease]; - } -} - -- (void)setPassword:(NSString *)newPassword -{ - @synchronized (self) - { - if (mPassword == newPassword) - return; - - [mPassword release]; - mPassword = [newPassword copy]; - - const char *newPasswordCString = [newPassword UTF8String]; - SecKeychainItemModifyAttributesAndData(mCoreKeychainItem, NULL, strlen(newPasswordCString), (void *)newPasswordCString); - } -} - -#pragma mark - -@dynamic username; -- (NSString *)username -{ - @synchronized (self) - { - return [[mUsername copy] autorelease]; - } -} - -- (void)setUsername:(NSString *)newUsername -{ - @synchronized (self) - { - if (mUsername == newUsername) - return; - - [mUsername release]; - mUsername = [newUsername copy]; - - const char *newUsernameCString = [newUsername UTF8String]; - [self _modifyAttributeWithTag:kSecAccountItemAttr toBeValue:(void *)newUsernameCString ofLength:strlen(newUsernameCString)]; - } -} - -#pragma mark - -@dynamic label; -- (NSString *)label -{ - @synchronized (self) - { - return [[mLabel copy] autorelease]; - } -} - -- (void)setLabel:(NSString *)newLabel -{ - @synchronized (self) - { - if (mLabel == newLabel) - return; - - [mLabel release]; - mLabel = [newLabel copy]; - - const char *newLabelCString = [newLabel UTF8String]; - [self _modifyAttributeWithTag:kSecLabelItemAttr toBeValue:(void *)newLabelCString ofLength:strlen(newLabelCString)]; - } -} - -#pragma mark - -#pragma mark Actions -- (void)removeFromKeychain -{ - NSAssert(mCoreKeychainItem, @"Core keychain item is nil. You cannot remove a keychain item that is not in the keychain already."); - - if (mCoreKeychainItem) - { - OSStatus resultStatus = SecKeychainItemDelete(mCoreKeychainItem); - if (resultStatus == noErr) - { - CFRelease(mCoreKeychainItem); - mCoreKeychainItem = nil; - } - } -} - -@end - -#pragma mark - -@implementation EMGenericKeychainItem - -- (id)_initWithCoreKeychainItem:(SecKeychainItemRef)item - serviceName:(NSString *)serviceName - username:(NSString *)username - password:(NSString *)password -{ - if ((self = [super _initWithCoreKeychainItem:item username:username password:password])) - { - mServiceName = [serviceName copy]; - return self; - } - return nil; -} - -+ (id)_genericKeychainItemWithCoreKeychainItem:(SecKeychainItemRef)coreKeychainItem - forServiceName:(NSString *)serviceName - username:(NSString *)username - password:(NSString *)password -{ - return [[[EMGenericKeychainItem alloc] _initWithCoreKeychainItem:coreKeychainItem - serviceName:serviceName - username:username - password:password] autorelease]; -} - -- (void)dealloc -{ - [mServiceName release]; - - [super dealloc]; -} - -#pragma mark - -+ (EMGenericKeychainItem *)genericKeychainItemForService:(NSString *)serviceName - withUsername:(NSString *)username -{ - if (!serviceName || !username) - return nil; - - const char *serviceNameCString = [serviceName UTF8String]; - const char *usernameCString = [username UTF8String]; - - UInt32 passwordLength = 0; - char *password = nil; - - SecKeychainItemRef item = nil; - OSStatus returnStatus = SecKeychainFindGenericPassword(NULL, strlen(serviceNameCString), serviceNameCString, strlen(usernameCString), usernameCString, &passwordLength, (void **)&password, &item); - if (returnStatus != noErr || !item) - { - if (_logsErrors) - NSLog(@"Error (%@) - %s", NSStringFromSelector(_cmd), GetMacOSStatusErrorString(returnStatus)); - return nil; - } - NSString *passwordString = [[[NSString alloc] initWithData:[NSData dataWithBytes:password length:passwordLength] encoding:NSUTF8StringEncoding] autorelease]; - SecKeychainItemFreeContent(NULL, password); - - return [EMGenericKeychainItem _genericKeychainItemWithCoreKeychainItem:item forServiceName:serviceName username:username password:passwordString]; -} - -+ (EMGenericKeychainItem *)addGenericKeychainItemForService:(NSString *)serviceName - withUsername:(NSString *)username - password:(NSString *)password -{ - if (!serviceName || !username || !password) - return nil; - - const char *serviceNameCString = [serviceName UTF8String]; - const char *usernameCString = [username UTF8String]; - const char *passwordCString = [password UTF8String]; - - SecKeychainItemRef item = nil; - OSStatus returnStatus = SecKeychainAddGenericPassword(NULL, strlen(serviceNameCString), serviceNameCString, strlen(usernameCString), usernameCString, strlen(passwordCString), (void *)passwordCString, &item); - - if (returnStatus != noErr || !item) - { - if (_logsErrors) - NSLog(@"Error (%@) - %s", NSStringFromSelector(_cmd), GetMacOSStatusErrorString(returnStatus)); - return nil; - } - return [EMGenericKeychainItem _genericKeychainItemWithCoreKeychainItem:item forServiceName:serviceName username:username password:password]; -} - -#pragma mark - -#pragma mark Generic Properties -@dynamic serviceName; -- (NSString *)serviceName -{ - @synchronized (self) - { - return [[mServiceName copy] autorelease]; - } -} - -- (void)setServiceName:(NSString *)newServiceName -{ - @synchronized (self) - { - if (mServiceName == newServiceName) - return; - - [mServiceName release]; - mServiceName = [newServiceName copy]; - - const char *newServiceNameCString = [newServiceName UTF8String]; - [self _modifyAttributeWithTag:kSecServiceItemAttr toBeValue:(void *)newServiceNameCString ofLength:strlen(newServiceNameCString)]; - } -} - -@end - -#pragma mark - -@implementation EMInternetKeychainItem - -- (id)_initWithCoreKeychainItem:(SecKeychainItemRef)item - server:(NSString *)server - username:(NSString *)username - password:(NSString *)password - path:(NSString *)path - port:(NSInteger)port - protocol:(SecProtocolType)protocol -{ - if ((self = [super _initWithCoreKeychainItem:item username:username password:password])) - { - mServer = [server copy]; - mPath = [path copy]; - mPort = port; - mProtocol = protocol; - - return self; - } - return nil; -} - -- (void)dealloc -{ - [mServer release]; - [mPath release]; - - [super dealloc]; -} - -+ (id)_internetKeychainItemWithCoreKeychainItem:(SecKeychainItemRef)coreKeychainItem - forServer:(NSString *)server - username:(NSString *)username - password:(NSString *)password - path:(NSString *)path - port:(NSInteger)port - protocol:(SecProtocolType)protocol -{ - return [[[EMInternetKeychainItem alloc] _initWithCoreKeychainItem:coreKeychainItem - server:server - username:username - password:password - path:path - port:port - protocol:protocol] autorelease]; -} - -#pragma mark - -+ (EMInternetKeychainItem *)internetKeychainItemForServer:(NSString *)server - withUsername:(NSString *)username - path:(NSString *)path - port:(NSInteger)port - protocol:(SecProtocolType)protocol -{ - if (!server || !username) - return nil; - - const char *serverCString = [server UTF8String]; - const char *usernameCString = [username UTF8String]; - const char *pathCString = [path UTF8String]; - - if (!path || [path length] == 0) - pathCString = ""; - - UInt32 passwordLength = 0; - char *password = nil; - - SecKeychainItemRef item = nil; - //0 is kSecAuthenticationTypeAny - OSStatus returnStatus = SecKeychainFindInternetPassword(NULL, strlen(serverCString), serverCString, 0, NULL, strlen(usernameCString), usernameCString, strlen(pathCString), pathCString, port, protocol, 0, &passwordLength, (void **)&password, &item); - - if (returnStatus != noErr && protocol == kSecProtocolTypeFTP) - { - //Some clients (like Transmit) still save passwords with kSecProtocolTypeFTPAccount, which was deprecated. Let's check for that. - protocol = kSecProtocolTypeFTPAccount; - returnStatus = SecKeychainFindInternetPassword(NULL, strlen(serverCString), serverCString, 0, NULL, strlen(usernameCString), usernameCString, strlen(pathCString), pathCString, port, protocol, 0, &passwordLength, (void **)&password, &item); - } - - if (returnStatus != noErr || !item) - { - if (_logsErrors) - NSLog(@"Error (%@) - %s", NSStringFromSelector(_cmd), GetMacOSStatusErrorString(returnStatus)); - return nil; - } - NSString *passwordString = [[[NSString alloc] initWithData:[NSData dataWithBytes:password length:passwordLength] encoding:NSUTF8StringEncoding] autorelease]; - SecKeychainItemFreeContent(NULL, password); - - return [EMInternetKeychainItem _internetKeychainItemWithCoreKeychainItem:item forServer:server username:username password:passwordString path:path port:port protocol:protocol]; -} - -+ (EMInternetKeychainItem *)addInternetKeychainItemForServer:(NSString *)server - withUsername:(NSString *)username - password:(NSString *)password - path:(NSString *)path - port:(NSInteger)port - protocol:(SecProtocolType)protocol -{ - if (!username || !server || !password) - return nil; - - const char *serverCString = [server UTF8String]; - const char *usernameCString = [username UTF8String]; - const char *passwordCString = [password UTF8String]; - const char *pathCString = [path UTF8String]; - - if (!path || [path length] == 0) - pathCString = ""; - - SecKeychainItemRef item = nil; - OSStatus returnStatus = SecKeychainAddInternetPassword(NULL, strlen(serverCString), serverCString, 0, NULL, strlen(usernameCString), usernameCString, strlen(pathCString), pathCString, port, protocol, kSecAuthenticationTypeDefault, strlen(passwordCString), (void *)passwordCString, &item); - - if (returnStatus != noErr || !item) - { - if (_logsErrors) - NSLog(@"Error (%@) - %s", NSStringFromSelector(_cmd), GetMacOSStatusErrorString(returnStatus)); - return nil; - } - return [EMInternetKeychainItem _internetKeychainItemWithCoreKeychainItem:item forServer:server username:username password:password path:path port:port protocol:protocol]; -} - -#pragma mark - -#pragma mark Internet Properties -@dynamic server; -- (NSString *)server -{ - @synchronized (self) - { - return [[mServer copy] autorelease]; - } -} - -- (void)setServer:(NSString *)newServer -{ - @synchronized (self) - { - if (mServer == newServer) - return; - - [mServer release]; - mServer = [newServer copy]; - - const char *newServerCString = [newServer UTF8String]; - [self _modifyAttributeWithTag:kSecServerItemAttr toBeValue:(void *)newServerCString ofLength:strlen(newServerCString)]; - } -} - -#pragma mark - -@dynamic path; -- (NSString *)path -{ - @synchronized (self) - { - return [[mPath copy] autorelease]; - } -} - -- (void)setPath:(NSString *)newPath -{ - if (mPath == newPath) - return; - - [mPath release]; - mPath = [newPath copy]; - - const char *newPathCString = [newPath UTF8String]; - [self _modifyAttributeWithTag:kSecPathItemAttr toBeValue:(void *)newPathCString ofLength:strlen(newPathCString)]; -} - -#pragma mark - -@dynamic port; -- (NSInteger)port -{ - @synchronized (self) - { - return mPort; - } -} - -- (void)setPort:(NSInteger)newPort -{ - @synchronized (self) - { - if (mPort == newPort) - return; - - mPort = newPort; - - UInt32 newPortValue = newPort; - [self _modifyAttributeWithTag:kSecPortItemAttr toBeValue:&newPortValue ofLength:sizeof(newPortValue)]; - } -} - -#pragma mark - -@dynamic protocol; -- (SecProtocolType)protocol -{ - @synchronized (self) - { - return mProtocol; - } -} - -- (void)setProtocol:(SecProtocolType)newProtocol -{ - @synchronized (self) - { - if (mProtocol == newProtocol) - return; - - mProtocol = newProtocol; - - [self _modifyAttributeWithTag:kSecProtocolItemAttr toBeValue:&newProtocol ofLength:sizeof(newProtocol)]; - } -} -@end \ No newline at end of file diff --git a/BitTicker/GraphView.h b/BitTicker/GraphView.h new file mode 100755 index 0000000..e04d8c0 --- /dev/null +++ b/BitTicker/GraphView.h @@ -0,0 +1,38 @@ +/* + BitTicker is Copyright 2012 Stephen Oliver + http://github.com/infincia + +*/ + +#import + +#import "CorePlot.h" + +#define TIMEFRAME_30MIN 100 +#define TIMEFRAME_12HOUR 200 +#define TIMEFRAME_24HOUR 300 + + +@interface GraphView : NSView { + + NSArray *_graphSource; + + + CPTXYGraph *_graph; + CPTGraphHostingView *hostingView; + CPTScatterPlot *dataSourceLinePlot; + + NSInteger timeframe; + +} + +-(IBAction)timeframeChanged:(id)sender; + +@property (nonatomic) NSInteger timeframe; + + +@property (strong) NSArray *graphSource; +@property (nonatomic, strong) CPTXYGraph *graph; + + +@end diff --git a/BitTicker/GraphView.m b/BitTicker/GraphView.m new file mode 100755 index 0000000..6fc709b --- /dev/null +++ b/BitTicker/GraphView.m @@ -0,0 +1,273 @@ +/* + BitTicker is Copyright 2012 Stephen Oliver + http://github.com/infincia + +*/ + +#import "GraphView.h" +#import "CorePlot.h" + + +@implementation GraphView +@synthesize graph = _graph; +@synthesize graphSource = _graphSource; +@synthesize timeframe; + +-(IBAction)timeframeChanged:(id)sender { + + NSSegmentedControl *control = (NSSegmentedControl*)sender; + + if ([control isSelectedForSegment:0]) { + + self.timeframe = TIMEFRAME_30MIN; + } + else if ([control isSelectedForSegment:1]) { + + self.timeframe = TIMEFRAME_12HOUR; + } + else if ([control isSelectedForSegment:2]) { + + self.timeframe = TIMEFRAME_24HOUR; + } + else { + // should never happen + NSAssert(1 == 0,@"Got invalid timeframe from control"); + } + [self configureTimeframe]; + +} + +-(void)awakeFromNib { + + NSInteger tf = [[NSUserDefaults standardUserDefaults] integerForKey:@"timeframe"]; + if (!tf) { + tf = TIMEFRAME_30MIN; + [[NSUserDefaults standardUserDefaults] setInteger:tf forKey:@"timeframe"]; + [[NSUserDefaults standardUserDefaults] synchronize]; + } + self.timeframe = tf; + _graph = [[CPTXYGraph alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)]; + CPTTheme *theme = [CPTTheme themeNamed:kCPTStocksTheme]; + [self.graph applyTheme:theme]; + + self.graph.cornerRadius = 6.0f; + + self.graph.paddingLeft = 0.0f; + self.graph.paddingTop = 0.0f; + self.graph.paddingRight = 0.0f; + self.graph.paddingBottom = 0.0f; + + + //graph.plotAreaFrame.masksToBorder = YES; + + self.graph.plotAreaFrame.cornerRadius = 6.0f; + self.graph.plotAreaFrame.paddingLeft = 45.0f; + self.graph.plotAreaFrame.paddingRight = 12.0f; + + self.graph.plotAreaFrame.paddingTop = 15.0f; + self.graph.plotAreaFrame.paddingBottom = 25.0f; + + //x axis line style + CPTMutableLineStyle *xlineStyle = [CPTMutableLineStyle lineStyle]; + xlineStyle.lineColor = [CPTColor redColor]; + xlineStyle.lineWidth = 1.0f; + + //y axis line style + CPTMutableLineStyle *ylineStyle = [CPTMutableLineStyle lineStyle]; + ylineStyle.lineColor = [CPTColor blueColor]; + ylineStyle.lineWidth = 1.0f; + + CPTXYAxisSet *axisSet = (CPTXYAxisSet *)self.graph.axisSet; + + // Tick locations + NSSet *majorTickLocations = [NSSet setWithObjects:[NSDecimalNumber zero], + [NSDecimalNumber numberWithUnsignedInteger:15], + nil]; + + + axisSet.xAxis.majorIntervalLength = CPTDecimalFromFloat(5); + axisSet.xAxis.minorTicksPerInterval = 1; + axisSet.xAxis.majorTickLineStyle = xlineStyle; + axisSet.xAxis.minorTickLineStyle = xlineStyle; + axisSet.xAxis.axisLineStyle = xlineStyle; + axisSet.xAxis.minorTickLength = 4.0f; + axisSet.xAxis.majorTickLength = 10.0f; + axisSet.xAxis.majorTickLocations = majorTickLocations; + axisSet.xAxis.title = nil; + + + // Text styles + CPTMutableTextStyle *axisTitleTextStyle = [CPTMutableTextStyle textStyle]; + axisTitleTextStyle.fontName = @"Helvetica-Bold"; + axisTitleTextStyle.color = [CPTColor whiteColor]; + axisTitleTextStyle.fontSize = 12.0; + + + axisSet.xAxis.titleTextStyle = axisTitleTextStyle; + axisSet.xAxis.titleOffset = 2.0f; + axisSet.xAxis.labelOffset = 0.0f; + axisSet.xAxis.labelingPolicy = CPTAxisLabelingPolicyAutomatic; + + + axisSet.yAxis.majorIntervalLength = CPTDecimalFromFloat(5); + axisSet.yAxis.minorTicksPerInterval = 0; + //axisSet.yAxis.majorTicksPerInterval = 1; + axisSet.yAxis.majorTickLineStyle = ylineStyle; + axisSet.yAxis.minorTickLineStyle = ylineStyle; + axisSet.yAxis.axisLineStyle = ylineStyle; + axisSet.yAxis.minorTickLength = 4.0f; + axisSet.yAxis.majorTickLength = 10.0f; + axisSet.yAxis.labelOffset = 3.0f; + + + + + NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init]; + [formatter setMaximumFractionDigits:0]; + [formatter setPositiveSuffix:@"$"]; + axisSet.yAxis.labelFormatter = formatter; + + + // Line plot with gradient fill + dataSourceLinePlot = [[CPTScatterPlot alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)]; + dataSourceLinePlot.identifier = @"Data Source Plot"; + CPTMutableLineStyle *graphlineStyle = [CPTMutableLineStyle lineStyle]; + graphlineStyle.lineColor = [CPTColor whiteColor]; + graphlineStyle.lineWidth = 1.0f; + dataSourceLinePlot.dataLineStyle = graphlineStyle; + + CPTColor *areaColor = [CPTColor colorWithComponentRed:1.0 green:1.0 blue:1.0 alpha:0.6]; + CPTGradient *areaGradient = [CPTGradient gradientWithBeginningColor:areaColor endingColor:[CPTColor whiteColor]]; + areaGradient.angle = 90.0f; + CPTFill *areaGradientFill = [CPTFill fillWithGradient:areaGradient]; + dataSourceLinePlot.areaFill = areaGradientFill; + dataSourceLinePlot.areaBaseValue = CPTDecimalFromDouble(0.0); + + dataSourceLinePlot.dataSource = self; + [self.graph addPlot:dataSourceLinePlot]; + + + hostingView = [[CPTGraphHostingView alloc] initWithFrame:NSRectFromCGRect(CGRectMake(0, 0, self.frame.size.width, self.frame.size.height))]; + + + hostingView.hostedGraph = self.graph; + + [self addSubview:hostingView]; + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateGraph:) name:@"MtGox-Ticker" object:nil]; + + //[graph reloadData]; + [self configureTimeframe]; + +} + + +- (void) updateGraph:(NSNotification *)notification { + self.graphSource = [[notification object] objectForKey:@"history"]; + + + + [self configureTimeframe]; +} + +-(void)configureTimeframe { + dispatch_async(dispatch_get_main_queue(), ^{ + CPTXYPlotSpace *plotSpace = (CPTXYPlotSpace *)self.graph.defaultPlotSpace; + CPTXYAxisSet *axisSet = (CPTXYAxisSet *)self.graph.axisSet; + + + float width_max = 0.0f; + float beginning = 0.0f; + float total = 1440.0f; + + + switch (self.timeframe) { + case TIMEFRAME_30MIN: + NSLog(@"Updating timeframe for 30 min"); + width_max = 30.0f; + //axisSet.xAxis.title = @"30 Mins"; + break; + case TIMEFRAME_12HOUR: + NSLog(@"Updating timeframe for 12 hours"); + width_max = 1220.0f; + //axisSet.xAxis.title = @"12 Hours"; + break; + case TIMEFRAME_24HOUR: + NSLog(@"Updating timeframe for 24 hours"); + width_max = 1440.0f; + //axisSet.xAxis.title = @"24 Hours"; + break; + default: + NSLog(@"NO TITLE"); + break; + } + + beginning = total - width_max; + NSArray *sortedArray = [self.graphSource sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) { + NSDictionary *one = (NSDictionary*)obj1; + NSDictionary *two = (NSDictionary*)obj2; + return [[one objectForKey:@"high"] compare:[two objectForKey:@"high"]]; + }]; + NSDictionary *highpoint = [sortedArray lastObject]; + NSInteger highestPrice = [[highpoint objectForKey:@"high"] intValue]; + //NSLog(@"Highest so far: %lu",highestRate); + + // Tick locations + NSSet *majorTickLocations = [NSSet setWithObjects:[NSDecimalNumber zero], + [NSDecimalNumber numberWithFloat:width_max], + nil]; + + axisSet.xAxis.majorTickLocations = majorTickLocations; + + + + axisSet.yAxis.majorTickLocations = [NSArray arrayWithObjects:[NSDecimalNumber numberWithFloat:0.0], [NSDecimalNumber numberWithInteger:highestPrice],[NSDecimalNumber numberWithInteger:highestPrice + 3],nil]; + + plotSpace.xRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromFloat(beginning) + length:CPTDecimalFromFloat(width_max)]; + + plotSpace.yRange = [CPTPlotRange plotRangeWithLocation:CPTDecimalFromUnsignedInteger(0) + length:CPTDecimalFromUnsignedInteger(highestPrice + 3)]; + + NSLog(@"Beginning: %f, Max: %f",beginning, width_max); + [self.graph reloadData]; + }); +} + + +#pragma mark - +#pragma mark Plot Data Source Methods + +-(NSUInteger)numberOfRecordsForPlot:(CPTPlot *)plot { + NSLog(@"Count: %ld",self.graphSource.count); + return self.graphSource.count; +} + +-(NSNumber *)numberForPlot:(CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index { + NSDictionary *ticker = [self.graphSource objectAtIndex:index]; + + double val = [[ticker objectForKey:@"last"] doubleValue]; + double time = 1440 - index; + + //NSLog(@"Graphing price: %f at %f",val,time); + if( fieldEnum == CPTScatterPlotFieldX ) { + return [NSNumber numberWithDouble:time]; + } + else { + return [NSNumber numberWithDouble:val]; + } +} + + +#pragma mark - View lifecycle + + +#ifdef __IPHONE_OS_VERSION_MIN_REQUIRED + +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { + // Return YES for supported orientations + return YES; +} +#endif + +@end diff --git a/BitTicker/JSON.h b/BitTicker/JSON.h deleted file mode 100755 index 89f1593..0000000 --- a/BitTicker/JSON.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - Copyright (C) 2009-2010 Stig Brautaset. 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 the author nor the names of its contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 OWNER 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. - */ - -/** - @mainpage A strict JSON parser and generator for Objective-C - - JSON (JavaScript Object Notation) is a lightweight data-interchange - format. This framework provides two apis for parsing and generating - JSON. One standard object-based and a higher level api consisting of - categories added to existing Objective-C classes. - - This framework does its best to be as strict as possible, both in what it accepts and what it generates. For example, it does not support trailing commas in arrays or objects. Nor does it support embedded comments, or anything else not in the JSON specification. This is considered a feature. - - @section Links - - @li Project home page. - @li Online version of the API documentation. - -*/ - - -// This setting of 1 is best if you copy the source into your project. -// The build transforms the 1 to a 0 when building the framework and static lib. - -#if 1 - -#import "SBJsonParser.h" -#import "SBJsonWriter.h" -#import "SBJsonStreamWriter.h" -#import "SBJsonStreamParser.h" -#import "SBJsonStreamParserAdapter.h" -#import "NSObject+JSON.h" - -#else - -#import -#import -#import -#import -#import -#import - -#endif diff --git a/BitTicker/Logo.icns b/BitTicker/Logo.icns old mode 100644 new mode 100755 diff --git a/BitTicker/MtGox.h b/BitTicker/MtGox.h new file mode 100755 index 0000000..aae7329 --- /dev/null +++ b/BitTicker/MtGox.h @@ -0,0 +1,18 @@ +/* + BitTicker is Copyright 2012 Stephen Oliver + http://github.com/infincia + +*/ + +#import +#import "dispatch/dispatch.h" + +@interface MtGox : NSObject { + NSMutableArray *history; + NSThread *loopThread; + dispatch_queue_t queue; + +} + + +@end diff --git a/BitTicker/MtGox.m b/BitTicker/MtGox.m new file mode 100755 index 0000000..1d1e355 --- /dev/null +++ b/BitTicker/MtGox.m @@ -0,0 +1,69 @@ +/* + BitTicker is Copyright 2012 Stephen Oliver + http://github.com/infincia + +*/ + +#import "dispatch/dispatch.h" + +#import "MtGox.h" + +#import "AFJSONRequestOperation.h" + +static NSString *mtgox_ticker_url = @"https://mtgox.com/code/data/ticker.php"; + +@implementation MtGox + +-(id)init { + self = [super init]; + history = [NSMutableArray new]; + + queue = dispatch_queue_create("com.infincia.BitTicker.mtgox.queue", nil); + loopThread = [[NSThread alloc] initWithTarget:self selector:@selector(loop) object:nil]; + [loopThread setName:@"loop"]; + [loopThread start]; + + return self; +} + + +- (void) loop { + @autoreleasepool { + NSLog(@"New loop"); + while (1) { + NSLog(@"Firing loop cycle"); + if ([[NSThread currentThread] isCancelled]) { + NSLog(@"Thread canceled"); + return; + } + NSURL *url = [NSURL URLWithString:mtgox_ticker_url]; + NSURLRequest *request = [NSURLRequest requestWithURL:url]; + AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) { + NSLog(@"Request successful"); + + NSMutableDictionary *message = [NSMutableDictionary new]; + NSDictionary *tickerDict = [JSON objectForKey:@"ticker"]; + + // capped stack, new tickers pushed on bottom, store 1440 minutes of data + if ([history count] >= 1440) { + [history removeLastObject]; + } + [history insertObject:tickerDict atIndex:0]; + + + [message setObject:tickerDict forKey:@"ticker"]; + [message setObject:history forKey:@"history"]; + [[NSNotificationCenter defaultCenter] postNotificationName:@"MtGox-Ticker" object:message]; + NSLog(@"Dispatched ticker data"); + } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) { + // + NSLog(@"Request failed"); + }]; + [operation start]; + [NSThread sleepForTimeInterval:60]; + } + } +} + + +@end diff --git a/BitTicker/MtGoxMarket.h b/BitTicker/MtGoxMarket.h deleted file mode 100644 index 444a1f2..0000000 --- a/BitTicker/MtGoxMarket.h +++ /dev/null @@ -1,17 +0,0 @@ -// -// MtGoxMarket.h -// Bitcoin Trader -// -// Created by Matt Stith on 4/30/11. -// Copyright 2011 Insomnia Addict. All rights reserved. -// - -#import - -#import "BitcoinMarket.h" - -@interface MtGoxMarket : BitcoinMarket { - -} - -@end diff --git a/BitTicker/MtGoxMarket.m b/BitTicker/MtGoxMarket.m deleted file mode 100644 index d73305c..0000000 --- a/BitTicker/MtGoxMarket.m +++ /dev/null @@ -1,103 +0,0 @@ -// -// MtGoxMarket.m -// Bitcoin Trader -// -// Created by Matt Stith on 4/30/11. -// Copyright 2011 Insomnia Addict. All rights reserved. -// - -#import "MtGoxMarket.h" - -#import "Trade.h" -#import "Ticker.h" -#import "EMKeychainItem.h" - -#define MTGOX_TICKER_URL @"https://mtgox.com/code/data/ticker.php" -#define MTGOX_TRADES_URL @"https://mtgox.com/code/data/getTrades.php" -#define MTGOX_MARKETDEPTH_URL @"https://mtgox.com/code/data/getDepth.php" -#define MTGOX_WALLET_URL @"https://mtgox.com/code/getFunds.php" - -@interface MtGoxMarket (Private) --(NSString*)makeURLStringWithSuffix:(NSString*)suffix; -@end - -@implementation MtGoxMarket - - --(void)fetchRecentTrades { - MSLog(@"Fetching recent trades..."); - [self downloadJsonDataFromURL:[NSURL URLWithString:MTGOX_TRADES_URL] callback:@selector(didFetchRecentTrades:)]; -} - --(void)fetchTicker { - MSLog(@"Fetching ticker..."); - [self downloadJsonDataFromURL:[NSURL URLWithString:MTGOX_TICKER_URL] callback:@selector(didFetchTickerData:)]; -} - --(void)fetchMarketDepth { - MSLog(@"Fetching market depth..."); - [self downloadJsonDataFromURL:[NSURL URLWithString:MTGOX_MARKETDEPTH_URL] callback:@selector(didFetchMarketDepth:)]; -} - --(void)fetchWallet { - MSLog(@"Fetching wallet..."); - NSString *username = [[NSUserDefaults standardUserDefaults] objectForKey:@"username"]; - EMGenericKeychainItem *keychainItem = [EMGenericKeychainItem genericKeychainItemForService:@"BitTicker-MtGox" withUsername:username]; - NSString *pass = keychainItem.password; - NSDictionary *post = [NSDictionary dictionaryWithObjectsAndKeys:username,@"name",pass,@"pass",nil]; - [self downloadJsonDataFromURL:[NSURL URLWithString:MTGOX_WALLET_URL] withPostData:post callback:@selector(didFetchWallet:)]; -} - --(void)didFetchRecentTrades:(NSArray*)tradeData { - NSMutableArray *trades = [NSMutableArray array]; - - for (NSDictionary *tradeDict in tradeData) { - Trade *newTrade = [[Trade alloc] init]; - newTrade.amount = [tradeDict objectForKey:@"amount"]; - newTrade.price = [tradeDict objectForKey:@"price"]; - newTrade.tid = [[tradeDict objectForKey:@"tid"] intValue]; - - newTrade.date = [NSDate dateWithTimeIntervalSince1970:[[tradeDict objectForKey:@"amount"] doubleValue]]; - - [trades addObject:newTrade]; - [newTrade release]; - } - MSLog(@"Got %i trades",trades.count); - - // Reverse the trades so 0 is the most recent - NSMutableArray *orderedTrades = [NSMutableArray array]; - NSEnumerator *reverseEnumerator = [trades reverseObjectEnumerator]; - id object; - - while ((object = [reverseEnumerator nextObject])) { - [orderedTrades addObject:object]; - } - - [_delegate bitcoinMarket:self didReceiveRecentTradesData:orderedTrades]; -} - --(void)didFetchTickerData:(NSDictionary*)tickerData { - NSDictionary *tickerDict = [tickerData objectForKey:@"ticker"]; - - Ticker *ticker = [[Ticker alloc] init]; - ticker.buy = [tickerDict objectForKey:@"buy"]; - ticker.sell = [tickerDict objectForKey:@"sell"]; - ticker.high = [tickerDict objectForKey:@"high"]; - ticker.low = [tickerDict objectForKey:@"low"]; - ticker.last = [tickerDict objectForKey:@"last"]; - ticker.volume = [tickerDict objectForKey:@"vol"]; - - [_delegate bitcoinMarket:self didReceiveTicker:ticker]; - [ticker release]; -} - --(void)didFetchMarketDepth:(NSDictionary*)marketDepth { - MSLog(@"Got %i asks and %i bids",[[marketDepth objectForKey:@"asks"] count],[[marketDepth objectForKey:@"bids"] count]); -} - --(void)didFetchWallet:(NSDictionary *)wallet { - NSLog(@"Dict: %@",wallet); - [_delegate bitcoinMarket:self didReceiveWallet:wallet]; -} - -@end diff --git a/BitTicker/NSMutableArray+Shift.h b/BitTicker/NSMutableArray+Shift.h new file mode 100755 index 0000000..09e818f --- /dev/null +++ b/BitTicker/NSMutableArray+Shift.h @@ -0,0 +1,15 @@ +// +// NSMutableArray+Shift.h +// BitTicker +// +// Created by steve on 6/15/11. +// Copyright 2011 none. All rights reserved. +// + +#import + + +@interface NSMutableArray (ShiftExtension) +// returns the first element of self and removes it +-(id)shift; +@end \ No newline at end of file diff --git a/BitTicker/NSMutableArray+Shift.m b/BitTicker/NSMutableArray+Shift.m new file mode 100755 index 0000000..d3a0cae --- /dev/null +++ b/BitTicker/NSMutableArray+Shift.m @@ -0,0 +1,19 @@ +// +// NSMutableArray+Shift.m +// BitTicker +// +// Created by steve on 6/15/11. +// Copyright 2011 none. All rights reserved. +// + +#import "NSMutableArray+Shift.h" + + +@implementation NSMutableArray (ShiftExtension) +-(id)shift { + if([self count] < 1) return nil; + id obj = [[[self objectAtIndex:0] retain] autorelease]; + [self removeObjectAtIndex:0]; + return obj; +} +@end diff --git a/BitTicker/NSMutableDictionary+IntegerKeys.h b/BitTicker/NSMutableDictionary+IntegerKeys.h deleted file mode 100644 index d0c68c0..0000000 --- a/BitTicker/NSMutableDictionary+IntegerKeys.h +++ /dev/null @@ -1,16 +0,0 @@ -// -// NSMutableDictionary+IntegerKeys.h -// Bitcoin Trader -// -// Created by Matt Stith on 4/30/11. -// Copyright 2011 Insomnia Addict. All rights reserved. -// - -#import - - -@interface NSMutableDictionary (NSMutableDictionary_IntegerKeys) --(void)setObject:(id)anObject forIntegerKey:(NSInteger)aKey; --(id)objectForIntegerKey:(NSInteger)aKey; --(void)removeObjectForInteger:(NSInteger)aKey; -@end diff --git a/BitTicker/NSMutableDictionary+IntegerKeys.m b/BitTicker/NSMutableDictionary+IntegerKeys.m deleted file mode 100644 index 4073488..0000000 --- a/BitTicker/NSMutableDictionary+IntegerKeys.m +++ /dev/null @@ -1,24 +0,0 @@ -// -// NSMutableDictionary+IntegerKeys.m -// Bitcoin Trader -// -// Created by Matt Stith on 4/30/11. -// Copyright 2011 Insomnia Addict. All rights reserved. -// - -#import "NSMutableDictionary+IntegerKeys.h" - - -@implementation NSMutableDictionary (NSMutableDictionary_IntegerKeys) - --(void)setObject:(id)anObject forIntegerKey:(NSInteger)aKey { - [self setObject:anObject forKey:[NSNumber numberWithInteger:aKey]]; -} - --(id)objectForIntegerKey:(NSInteger)aKey { - return [self objectForKey:[NSNumber numberWithInteger:aKey]]; -} --(void)removeObjectForInteger:(NSInteger)aKey { - [self removeObjectForKey:[NSNumber numberWithInteger:aKey]]; -} -@end diff --git a/BitTicker/NSObject+JSON.h b/BitTicker/NSObject+JSON.h deleted file mode 100755 index 4a9e760..0000000 --- a/BitTicker/NSObject+JSON.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - Copyright (C) 2009 Stig Brautaset. 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 the author nor the names of its contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 OWNER 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. - */ - -#import - -#pragma mark JSON Writing - -/// Adds JSON generation to NSArray -@interface NSArray (NSArray_SBJsonWriting) - -/// Returns a string containing the receiver encoded in JSON. -- (NSString *)JSONRepresentation; - -@end - - -/// Adds JSON generation to NSArray -@interface NSDictionary (NSDictionary_SBJsonWriting) - -/// Returns a string containing the receiver encoded in JSON. -- (NSString *)JSONRepresentation; - -@end - -#pragma mark JSON Parsing - -/// Adds JSON parsing methods to NSString -@interface NSString (NSString_SBJsonParsing) - -/// Returns the NSDictionary or NSArray represented by the receiver's JSON representation, or nil on error -- (id)JSONValue; - -@end - - diff --git a/BitTicker/NSObject+JSON.m b/BitTicker/NSObject+JSON.m deleted file mode 100755 index 9c7ebaf..0000000 --- a/BitTicker/NSObject+JSON.m +++ /dev/null @@ -1,60 +0,0 @@ -/* - Copyright (C) 2009 Stig Brautaset. 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 the author nor the names of its contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 OWNER 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. - */ - -#import "NSObject+JSON.h" -#import "SBJsonWriter.h" -#import "SBJsonParser.h" - -@implementation NSObject (NSObject_SBJsonWriting) - -- (NSString *)JSONRepresentation { - SBJsonWriter *jsonWriter = [SBJsonWriter new]; - NSString *json = [jsonWriter stringWithObject:self]; - if (!json) - NSLog(@"-JSONRepresentation failed. Error is: %@", jsonWriter.error); - [jsonWriter release]; - return json; -} - -@end - - - -@implementation NSString (NSString_SBJsonParsing) - -- (id)JSONValue { - SBJsonParser *jsonParser = [SBJsonParser new]; - id repr = [jsonParser objectWithString:self]; - if (!repr) - NSLog(@"-JSONValue failed. Error is: %@", jsonParser.error); - [jsonParser release]; - return repr; -} - -@end diff --git a/BitTicker/RequestHandler.h b/BitTicker/RequestHandler.h deleted file mode 100644 index fd8ec99..0000000 --- a/BitTicker/RequestHandler.h +++ /dev/null @@ -1,34 +0,0 @@ -// -// RequestHandler.h -// Bitcoin Trader -// -// Created by Matt Stith on 4/30/11. -// Copyright 2011 Insomnia Addict. All rights reserved. -// -// Wrapper around NSURLRequest which will handle multiple requests -// a little more gracefully - -#import - -#import "RequestHandlerDelegate.h" -#import "NSMutableDictionary+IntegerKeys.h" - - -@interface RequestHandler : NSObject { - id _delegate; - NSInteger _currentTag; - NSMutableDictionary *_connectionData; - NSMutableDictionary *_connections; // For sanity in dealloc - NSInteger _activeRequests; -} - -// Initializer --(id)initWithDelegate:(id)requestDelegate; - -// Starts processing a connection, returns a tag --(NSInteger)startConnection:(NSURLRequest*)newRequest; - --(void)cancelAllRequests; - -@property (nonatomic, assign) iddelegate; -@end diff --git a/BitTicker/RequestHandler.m b/BitTicker/RequestHandler.m deleted file mode 100644 index 2176db5..0000000 --- a/BitTicker/RequestHandler.m +++ /dev/null @@ -1,103 +0,0 @@ -// -// RequestHandler.m -// Bitcoin Trader -// -// Created by Matt Stith on 4/30/11. -// Copyright 2011 Insomnia Addict. All rights reserved. -// - -#import "RequestHandler.h" - -#import "TaggedNSURLConnection.h" - -@implementation RequestHandler -@synthesize delegate=_delegate; - --(id)initWithDelegate:(id)requestDelegate { - if (!(self = [super init])) return self; - - if (!requestDelegate) { - MSLog(@"RequestHandler requires a delegate!"); - [self release]; - return false; - } - - self.delegate = requestDelegate; - _connectionData = [[NSMutableDictionary alloc] init]; - - _currentTag = 0; - _activeRequests = 0; - - return self; -} - --(void)dealloc { - [self cancelAllRequests]; - [_connections release]; - [_connectionData release]; - [super dealloc]; -} - --(NSInteger)startConnection:(NSURLRequest*)newRequest { - if (!newRequest) { - MSLog(@"No request passed to startConnection"); - return false; - } - - TaggedNSURLConnection *connection = [[TaggedNSURLConnection alloc] initWithRequest:newRequest delegate:self]; - - NSInteger newTag = _currentTag++; - connection.tag = newTag; - - [_connections setObject:connection forIntegerKey:newTag]; - [_connectionData setObject:[NSMutableData dataWithLength:0] forIntegerKey:newTag]; - [connection start]; - _activeRequests++; - - [connection release]; - - return newTag; -} --(void)cancelAllRequests { - for(NSString *key in _connections) { - TaggedNSURLConnection *connection = [_connections objectForKey:key]; - [connection cancel]; - } - _activeRequests = 0; -} -#pragma mark - NSURLConnection methods -- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { - TaggedNSURLConnection *taggedConnection = (TaggedNSURLConnection*)connection; - - NSMutableData *existingData = [_connectionData objectForIntegerKey:taggedConnection.tag]; - [existingData appendData:data]; -} - -- (void)connectionDidFinishLoading:(NSURLConnection *)connection { - TaggedNSURLConnection *taggedConnection = (TaggedNSURLConnection*)connection; - _activeRequests--; - - [_delegate request:taggedConnection.tag didFinishWithData:[_connectionData objectForIntegerKey:taggedConnection.tag]]; - - [_connections removeObjectForInteger:taggedConnection.tag]; - [_connectionData removeObjectForInteger:taggedConnection.tag]; - -} - -- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { - //TaggedNSURLConnection *taggedConnection = (TaggedNSURLConnection*)connection; - - //MSLog(@"Connection %i got response %@", taggedConnection.tag, response); -} - -- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { - TaggedNSURLConnection *taggedConnection = (TaggedNSURLConnection*)connection; - MSLog(@"Connection %i failed with error %@", taggedConnection.tag, error); - _activeRequests--; - [_delegate request:taggedConnection.tag didFailWithError:error]; - - [_connections removeObjectForInteger:taggedConnection.tag]; - [_connectionData removeObjectForInteger:taggedConnection.tag]; - -} -@end diff --git a/BitTicker/RequestHandlerDelegate.h b/BitTicker/RequestHandlerDelegate.h deleted file mode 100644 index 1a04ef0..0000000 --- a/BitTicker/RequestHandlerDelegate.h +++ /dev/null @@ -1,15 +0,0 @@ -// -// RequestHandlerDelegate.h -// Bitcoin Trader -// -// Created by Matt Stith on 4/30/11. -// Copyright 2011 Insomnia Addict. All rights reserved. -// - -#import - -@protocol RequestHandlerDelegate - --(void)request:(NSInteger)tag didFinishWithData:(NSData*)data; --(void)request:(NSInteger)tag didFailWithError:(NSError*)error; -@end diff --git a/BitTicker/SBJsonParser.h b/BitTicker/SBJsonParser.h deleted file mode 100755 index 8f3d0a3..0000000 --- a/BitTicker/SBJsonParser.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - Copyright (C) 2009 Stig Brautaset. 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 the author nor the names of its contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 OWNER 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. - */ - -#import - -/** - @brief The JSON parser class. - - JSON is mapped to Objective-C types in the following way: - - @li Null -> NSNull - @li String -> NSMutableString - @li Array -> NSMutableArray - @li Object -> NSMutableDictionary - @li Boolean -> NSNumber (initialised with -initWithBool:) - @li Number -> (NSNumber | NSDecimalNumber) - - Since Objective-C doesn't have a dedicated class for boolean values, these turns into NSNumber - instances. These are initialised with the -initWithBool: method, and - round-trip back to JSON properly. (They won't silently suddenly become 0 or 1; they'll be - represented as 'true' and 'false' again.) - - As an optimisation short JSON integers turn into NSNumber instances, while complex ones turn into NSDecimalNumber instances. - We can thus avoid any loss of precision as JSON allows ridiculously large numbers. - - */ - -@interface SBJsonParser : NSObject { - id value; - NSString *error; - NSUInteger depth, maxDepth; - -} - -/** - @brief The maximum recursing depth. - - Defaults to 512. If the input is nested deeper than this the input will be deemed to be - malicious and the parser returns nil, signalling an error. ("Nested too deep".) You can - turn off this security feature by setting the maxDepth value to 0. - */ -@property NSUInteger maxDepth; - -/** - @brief Return an error trace, or nil if there was no errors. - - Note that this method returns the trace of the last method that failed. - You need to check the return value of the call you're making to figure out - if the call actually failed, before you know call this method. - */ -@property(copy) NSString *error; - -/** - @brief Return the object represented by the given NSData object. - - The data *must* be UTF8 encoded. - @param data the data to parse. - - */ -- (id)objectWithData:(NSData*)data; - -/** - @brief Return the object represented by the given string - - Returns the object represented by the passed-in string or nil on error. The returned object can be - a string, number, boolean, null, array or dictionary. - - @param repr the json string to parse - */ -- (id)objectWithString:(NSString *)repr; - -/** - @brief Return the object represented by the given string - - Returns the object represented by the passed-in string or nil on error. The returned object can be - a string, number, boolean, null, array or dictionary. - - @param jsonText the json string to parse - @param error pointer to an NSError object to populate on error - */ - -- (id)objectWithString:(NSString*)jsonText - error:(NSError**)error; - -@end - - diff --git a/BitTicker/SBJsonParser.m b/BitTicker/SBJsonParser.m deleted file mode 100755 index 24ccb86..0000000 --- a/BitTicker/SBJsonParser.m +++ /dev/null @@ -1,120 +0,0 @@ -/* - Copyright (C) 2009,2010 Stig Brautaset. 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 the author nor the names of its contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 OWNER 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. - */ - -#import "SBJsonParser.h" -#import "SBJsonStreamParser.h" -#import "SBJsonStreamParserAdapter.h" - -@interface SBJsonParser () -@end - - -@implementation SBJsonParser - -@synthesize maxDepth; -@synthesize error; - -#pragma mark SBJsonStreamParserAdapterDelegate - -- (void)parser:(SBJsonStreamParser*)parser foundArray:(NSArray *)array { - value = [array retain]; -} - -- (void)parser:(SBJsonStreamParser*)parser foundObject:(NSDictionary *)dict { - value = [dict retain]; -} - -- (id)init { - self = [super init]; - if (self) - self.maxDepth = 512; - return self; -} - -- (void)dealloc { - [error release]; - [super dealloc]; -} - -#pragma mark Methods - -- (id)objectWithData:(NSData *)data { - - if (!data) { - self.error = @"Input was 'nil'"; - return nil; - } - - SBJsonStreamParserAdapter *adapter = [SBJsonStreamParserAdapter new]; - adapter.delegate = self; - - SBJsonStreamParser *parser = [SBJsonStreamParser new]; - parser.maxDepth = self.maxDepth; - parser.delegate = adapter; - - id retval = nil; - switch ([parser parse:data]) { - case SBJsonStreamParserComplete: - retval = [value autorelease]; - break; - - case SBJsonStreamParserWaitingForData: - self.error = @"Didn't find full object before EOF"; - break; - - case SBJsonStreamParserError: - self.error = parser.error; - break; - } - - - [adapter release]; - [parser release]; - - return retval; -} - -- (id)objectWithString:(NSString *)repr { - return [self objectWithData:[repr dataUsingEncoding:NSUTF8StringEncoding]]; -} - -- (id)objectWithString:(NSString*)repr error:(NSError**)error_ { - id tmp = [self objectWithString:repr]; - if (tmp) - return tmp; - - if (error_) { - NSDictionary *ui = [NSDictionary dictionaryWithObjectsAndKeys:error, NSLocalizedDescriptionKey, nil]; - *error_ = [NSError errorWithDomain:@"org.brautaset.json.parser.ErrorDomain" code:0 userInfo:ui]; - } - - return nil; -} - -@end diff --git a/BitTicker/SBJsonStreamParser.h b/BitTicker/SBJsonStreamParser.h deleted file mode 100755 index efc4e54..0000000 --- a/BitTicker/SBJsonStreamParser.h +++ /dev/null @@ -1,135 +0,0 @@ -/* - Copyright (c) 2010, Stig Brautaset. - 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 the the author nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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. - */ - -#import - -@class SBJsonTokeniser; -@class SBJsonStreamParser; -@class SBJsonStreamParserState; - -typedef enum { - SBJsonStreamParserComplete, - SBJsonStreamParserWaitingForData, - SBJsonStreamParserError, -} SBJsonStreamParserStatus; - - -/** - @brief Delegate for interacting directly with the stream parser - - You will most likely find it much more convenient to implement the - SBJsonStreamParserAdapterDelegate protocol instead. - */ -@protocol SBJsonStreamParserDelegate - -/// Called when object start is found -- (void)parserFoundObjectStart:(SBJsonStreamParser*)parser; - -/// Called when object key is found -- (void)parser:(SBJsonStreamParser*)parser foundObjectKey:(NSString*)key; - -/// Called when object end is found -- (void)parserFoundObjectEnd:(SBJsonStreamParser*)parser; - -/// Called when array start is found -- (void)parserFoundArrayStart:(SBJsonStreamParser*)parser; - -/// Called when array end is found -- (void)parserFoundArrayEnd:(SBJsonStreamParser*)parser; - -/// Called when a boolean value is found -- (void)parser:(SBJsonStreamParser*)parser foundBoolean:(BOOL)x; - -/// Called when a null value is found -- (void)parserFoundNull:(SBJsonStreamParser*)parser; - -/// Called when a number is found -- (void)parser:(SBJsonStreamParser*)parser foundNumber:(NSNumber*)num; - -/// Called when a string is found -- (void)parser:(SBJsonStreamParser*)parser foundString:(NSString*)string; - -@end - - -/** - @brief JSON Stream-parser class - - */ -@interface SBJsonStreamParser : NSObject { - BOOL multi; - id delegate; - SBJsonTokeniser *tokeniser; - SBJsonStreamParserState **states; - NSUInteger depth, maxDepth; - NSString *error; -} - -/** - @brief Expect multiple documents separated by whitespace - - If you set this property to true the parser will never return SBJsonStreamParserComplete. - Once an object is completed it will expect another object to follow, separated only by whitespace. - - @see The TwitterStream example project. - */ -@property BOOL multi; - -/// Set this to the object you want to receive messages -@property (assign) id delegate; - -/// The current depth in the json document (each [ and { each count 1) -@property (readonly) NSUInteger depth; - -/// The max depth to allow the parser to reach -@property NSUInteger maxDepth; - -/// @internal -@property (readonly) SBJsonStreamParserState **states; - -/// Holds the error after SBJsonStreamParserError was returned -@property (copy) NSString *error; - -/** - @brief Parse some JSON - - The JSON is assumed to be UTF8 encoded. This can be a full JSON document, or a part of one. - - @return - @li SBJsonStreamParserComplete if a full document was found - @li SBJsonStreamParserWaitingForData if a partial document was found and more data is required to complete it - @li SBJsonStreamParserError if an error occured. (See the error property for details in this case.) - - */ -- (SBJsonStreamParserStatus)parse:(NSData*)data; - -@end diff --git a/BitTicker/SBJsonStreamParser.m b/BitTicker/SBJsonStreamParser.m deleted file mode 100755 index b6315a1..0000000 --- a/BitTicker/SBJsonStreamParser.m +++ /dev/null @@ -1,273 +0,0 @@ -/* - Copyright (c) 2010, Stig Brautaset. - 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 the the author nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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. - */ - -#import "SBJsonStreamParser.h" -#import "SBJsonTokeniser.h" -#import "SBJsonStreamParserState.h" - - -@implementation SBJsonStreamParser - -@synthesize multi; -@synthesize error; -@synthesize delegate; -@dynamic maxDepth; -@synthesize states; -@synthesize depth; - -#pragma mark Housekeeping - -- (id)init { - self = [super init]; - if (self) { - tokeniser = [SBJsonTokeniser new]; - maxDepth = 512; - states = calloc(maxDepth, sizeof(SBJsonStreamParserState*)); - NSAssert(states, @"States not initialised"); - states[0] = [SBJsonStreamParserStateStart sharedInstance]; - } - return self; -} - -- (void)dealloc { - self.error = nil; - free(states); - [tokeniser release]; - [super dealloc]; -} - -#pragma mark Methods - -- (NSString*)tokenName:(sbjson_token_t)token { - switch (token) { - case sbjson_token_array_start: - return @"start of array"; - break; - - case sbjson_token_array_end: - return @"end of array"; - break; - - case sbjson_token_double: - case sbjson_token_integer: - return @"number"; - break; - - case sbjson_token_string: - case sbjson_token_string_encoded: - return @"string"; - break; - - case sbjson_token_true: - case sbjson_token_false: - return @"boolean"; - break; - - case sbjson_token_null: - return @"null"; - break; - - case sbjson_token_key_value_separator: - return @"key-value separator"; - break; - - case sbjson_token_separator: - return @"value separator"; - break; - - case sbjson_token_object_start: - return @"start of object"; - break; - - case sbjson_token_object_end: - return @"end of object"; - break; - - case sbjson_token_eof: - case sbjson_token_error: - break; - } - NSAssert(NO, @"Should not get here"); - return @""; -} - - -- (SBJsonStreamParserStatus)parse:(NSData *)data_ { - [tokeniser appendData:data_]; - - const char *buf; - NSUInteger len; - - for (;;) { - if ([states[depth] parserShouldStop:self]) - return [states[depth] parserShouldReturn:self]; - - sbjson_token_t tok = [tokeniser next]; - - switch (tok) { - case sbjson_token_eof: - return SBJsonStreamParserWaitingForData; - break; - - case sbjson_token_error: - states[depth] = kSBJsonStreamParserStateError; - self.error = tokeniser.error; - return SBJsonStreamParserError; - break; - - default: - - if (![states[depth] parser:self shouldAcceptToken:tok]) { - NSString *tokenName = [self tokenName:tok]; - NSString *stateName = [states[depth] name]; - NSLog(@"STATE: %@", states[depth]); - self.error = [NSString stringWithFormat:@"Token '%@' not expected %@", tokenName, stateName]; - states[depth] = kSBJsonStreamParserStateError; - return SBJsonStreamParserError; - } - - switch (tok) { - case sbjson_token_object_start: - if (depth >= maxDepth) { - self.error = [NSString stringWithFormat:@"Parser exceeded max depth of %lu", maxDepth]; - states[depth] = kSBJsonStreamParserStateError; - - } else { - [delegate parserFoundObjectStart:self]; - states[++depth] = kSBJsonStreamParserStateObjectStart; - } - break; - - case sbjson_token_object_end: - [states[--depth] parser:self shouldTransitionTo:tok]; - [delegate parserFoundObjectEnd:self]; - break; - - case sbjson_token_array_start: - if (depth >= maxDepth) { - self.error = [NSString stringWithFormat:@"Parser exceeded max depth of %lu", maxDepth]; - states[depth] = kSBJsonStreamParserStateError; - } else { - [delegate parserFoundArrayStart:self]; - states[++depth] = kSBJsonStreamParserStateArrayStart; - } - break; - - case sbjson_token_array_end: - [states[--depth] parser:self shouldTransitionTo:tok]; - [delegate parserFoundArrayEnd:self]; - break; - - case sbjson_token_separator: - case sbjson_token_key_value_separator: - [states[depth] parser:self shouldTransitionTo:tok]; - break; - - case sbjson_token_true: - [delegate parser:self foundBoolean:YES]; - [states[depth] parser:self shouldTransitionTo:tok]; - break; - - case sbjson_token_false: - [delegate parser:self foundBoolean:NO]; - [states[depth] parser:self shouldTransitionTo:tok]; - break; - - case sbjson_token_null: - [delegate parserFoundNull:self]; - [states[depth] parser:self shouldTransitionTo:tok]; - break; - - case sbjson_token_integer: - case sbjson_token_double: - if ([tokeniser getToken:&buf length:&len]) { - NSNumber *number; - if (tok == sbjson_token_integer && len < 12) { - char *e = NULL; - long l = strtol(buf, &e, 0); - NSAssert((e-buf) == len, @"unexpected length"); - number = [NSNumber numberWithLong:l]; - - } else if (tok == sbjson_token_double && len < 7) { - char *e = NULL; - double d = strtod(buf, &e); - NSAssert((e-buf) == len, @"unexpected length"); - number = [NSNumber numberWithDouble:d]; - - } else { - NSData *data = [NSData dataWithBytes:buf length:len]; - NSString *string = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]; - number = [[[NSDecimalNumber alloc] initWithString:string] autorelease]; - } - NSParameterAssert(number); - [delegate parser:self foundNumber:number]; - - } - [states[depth] parser:self shouldTransitionTo:tok]; - break; - - case sbjson_token_string: - case sbjson_token_string_encoded: { - NSString *string; - if (tok == sbjson_token_string) { - [tokeniser getToken:&buf length:&len]; - string = [[[NSString alloc] initWithBytes:buf+1 length:len-2 encoding:NSUTF8StringEncoding] autorelease]; - } else { - string = [tokeniser getDecodedStringToken]; - } - NSParameterAssert(string); - if ([states[depth] needKey]) - [delegate parser:self foundObjectKey:string]; - else - [delegate parser:self foundString:string]; - [states[depth] parser:self shouldTransitionTo:tok]; - break; - } - default: - break; - } - break; - } - } - return SBJsonStreamParserComplete; -} - -#pragma mark Private methods - -- (void)setMaxDepth:(NSUInteger)x { - NSAssert(x, @"maxDepth must be greater than 0"); - maxDepth = x; - states = realloc(states, x); - NSAssert(states, @"Failed to reallocate more memory for states"); -} - -@end diff --git a/BitTicker/SBJsonStreamParserAdapter.h b/BitTicker/SBJsonStreamParserAdapter.h deleted file mode 100755 index 3fcf571..0000000 --- a/BitTicker/SBJsonStreamParserAdapter.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - Copyright (c) 2010, Stig Brautaset. - 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 the the author nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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. - */ - -#import -#import "SBJsonStreamParser.h" - -typedef enum { - SBJsonStreamParserAdapterNone, - SBJsonStreamParserAdapterArray, - SBJsonStreamParserAdapterObject, -} SBJsonStreamParserAdapterType; - -/** - @brief Delegate for getting objects & arrays from the stream parser adapter - - You will most likely find it much more convenient to implement this - than the raw SBJsonStreamParserDelegate protocol. - - @see The TwitterStream example project. - */ -@protocol SBJsonStreamParserAdapterDelegate - -/// Called when a JSON array is found -- (void)parser:(SBJsonStreamParser*)parser foundArray:(NSArray*)array; - -/// Called when a JSON object is found -- (void)parser:(SBJsonStreamParser*)parser foundObject:(NSDictionary*)dict; - -@end - - -@interface SBJsonStreamParserAdapter : NSObject { - id delegate; - NSUInteger skip, depth; - __weak NSMutableArray *array; - __weak NSMutableDictionary *dict; - NSMutableArray *keyStack; - NSMutableArray *stack; - - SBJsonStreamParserAdapterType currentType; -} - -/** - @brief How many levels to skip - - This is useful for parsing HUGE JSON documents, particularly if it consists of an - outer array and multiple objects. - - If you set this to N it will skip the outer N levels and call the -parser:foundArray: - or -parser:foundObject: methods for each of the inner objects, as appropriate. - - @see The StreamParserIntegrationTest.m file for examples -*/ -@property NSUInteger skip; - -/// Set this to the object you want to receive messages -@property (assign) id delegate; - -@end diff --git a/BitTicker/SBJsonStreamParserAdapter.m b/BitTicker/SBJsonStreamParserAdapter.m deleted file mode 100755 index 3b5e3dd..0000000 --- a/BitTicker/SBJsonStreamParserAdapter.m +++ /dev/null @@ -1,171 +0,0 @@ -/* - Copyright (c) 2010, Stig Brautaset. - 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 the the author nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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. - */ - -#import "SBJsonStreamParserAdapter.h" - -@interface SBJsonStreamParserAdapter () - -- (void)pop; -- (void)parser:(SBJsonStreamParser*)parser found:(id)obj; - -@end - - - -@implementation SBJsonStreamParserAdapter - -@synthesize delegate; -@synthesize skip; - -#pragma mark Housekeeping - -- (id)init { - self = [super init]; - if (self) { - keyStack = [[NSMutableArray alloc] initWithCapacity:32]; - stack = [[NSMutableArray alloc] initWithCapacity:32]; - - currentType = SBJsonStreamParserAdapterNone; - } - return self; -} - -- (void)dealloc { - [keyStack release]; - [stack release]; - [super dealloc]; -} - -#pragma mark Private methods - -- (void)pop { - [stack removeLastObject]; - array = nil; - dict = nil; - currentType = SBJsonStreamParserAdapterNone; - - id value = [stack lastObject]; - - if ([value isKindOfClass:[NSArray class]]) { - array = value; - currentType = SBJsonStreamParserAdapterArray; - } else if ([value isKindOfClass:[NSDictionary class]]) { - dict = value; - currentType = SBJsonStreamParserAdapterObject; - } -} - -- (void)parser:(SBJsonStreamParser*)parser found:(id)obj { - NSParameterAssert(obj); - - switch (currentType) { - case SBJsonStreamParserAdapterArray: - [array addObject:obj]; - break; - - case SBJsonStreamParserAdapterObject: - NSParameterAssert(keyStack.count); - [dict setObject:obj forKey:[keyStack lastObject]]; - [keyStack removeLastObject]; - break; - - case SBJsonStreamParserAdapterNone: - if ([obj isKindOfClass:[NSArray class]]) { - [delegate parser:parser foundArray:obj]; - } else { - [delegate parser:parser foundObject:obj]; - } - break; - - default: - break; - } -} - - -#pragma mark Delegate methods - -- (void)parserFoundObjectStart:(SBJsonStreamParser*)parser { - if (++depth > skip) { - dict = [[NSMutableDictionary new] autorelease]; - [stack addObject:dict]; - currentType = SBJsonStreamParserAdapterObject; - } -} - -- (void)parser:(SBJsonStreamParser*)parser foundObjectKey:(NSString*)key_ { - [keyStack addObject:key_]; -} - -- (void)parserFoundObjectEnd:(SBJsonStreamParser*)parser { - if (depth-- > skip) { - id value = [dict retain]; - [self pop]; - [self parser:parser found:value]; - [value release]; - } -} - -- (void)parserFoundArrayStart:(SBJsonStreamParser*)parser { - if (++depth > skip) { - array = [[NSMutableArray new] autorelease]; - [stack addObject:array]; - currentType = SBJsonStreamParserAdapterArray; - } -} - -- (void)parserFoundArrayEnd:(SBJsonStreamParser*)parser { - if (depth-- > skip) { - id value = [array retain]; - [self pop]; - [self parser:parser found:value]; - [value release]; - } -} - -- (void)parser:(SBJsonStreamParser*)parser foundBoolean:(BOOL)x { - [self parser:parser found:[NSNumber numberWithBool:x]]; -} - -- (void)parserFoundNull:(SBJsonStreamParser*)parser { - [self parser:parser found:[NSNull null]]; -} - -- (void)parser:(SBJsonStreamParser*)parser foundNumber:(NSNumber*)num { - [self parser:parser found:num]; -} - -- (void)parser:(SBJsonStreamParser*)parser foundString:(NSString*)string { - [self parser:parser found:string]; -} - -@end diff --git a/BitTicker/SBJsonStreamParserState.h b/BitTicker/SBJsonStreamParserState.h deleted file mode 100755 index 1103ed0..0000000 --- a/BitTicker/SBJsonStreamParserState.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - Copyright (c) 2010, Stig Brautaset. - 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 the the author nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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. - */ - -#import - -#import "SBJsonTokeniser.h" -#import "SBJsonStreamParser.h" - -@interface SBJsonStreamParserState : NSObject - -- (BOOL)parser:(SBJsonStreamParser*)parser shouldAcceptToken:(sbjson_token_t)token; -- (BOOL)parserShouldStop:(SBJsonStreamParser*)parser; -- (SBJsonStreamParserStatus)parserShouldReturn:(SBJsonStreamParser*)parser; -- (void)parser:(SBJsonStreamParser*)parser shouldTransitionTo:(sbjson_token_t)tok; -- (BOOL)needKey; - -- (NSString*)name; - -@end - -@interface SBJsonStreamParserStateStart : SBJsonStreamParserState -+ (id)sharedInstance; -@end - -@interface SBJsonStreamParserStateComplete : SBJsonStreamParserState -@end - -@interface SBJsonStreamParserStateError : SBJsonStreamParserState -@end - - -@interface SBJsonStreamParserStateObjectStart : SBJsonStreamParserState -@end - -@interface SBJsonStreamParserStateObjectGotKey : SBJsonStreamParserState -@end - -@interface SBJsonStreamParserStateObjectSeparator : SBJsonStreamParserState -@end - -@interface SBJsonStreamParserStateObjectGotValue : SBJsonStreamParserState -@end - -@interface SBJsonStreamParserStateObjectNeedKey : SBJsonStreamParserState -@end - -@interface SBJsonStreamParserStateArrayStart : SBJsonStreamParserState -@end - -@interface SBJsonStreamParserStateArrayGotValue : SBJsonStreamParserState -@end - -@interface SBJsonStreamParserStateArrayNeedValue : SBJsonStreamParserState -@end - -extern SBJsonStreamParserStateStart *kSBJsonStreamParserStateStart; -extern SBJsonStreamParserStateError *kSBJsonStreamParserStateError; -extern SBJsonStreamParserStateObjectStart *kSBJsonStreamParserStateObjectStart; -extern SBJsonStreamParserStateArrayStart *kSBJsonStreamParserStateArrayStart; - diff --git a/BitTicker/SBJsonStreamParserState.m b/BitTicker/SBJsonStreamParserState.m deleted file mode 100755 index a25c664..0000000 --- a/BitTicker/SBJsonStreamParserState.m +++ /dev/null @@ -1,370 +0,0 @@ -/* - Copyright (c) 2010, Stig Brautaset. - 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 the the author nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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. - */ - -#import "SBJsonStreamParserState.h" -#import "SBJsonStreamParser.h" - -SBJsonStreamParserStateStart *kSBJsonStreamParserStateStart; -SBJsonStreamParserStateError *kSBJsonStreamParserStateError; -static SBJsonStreamParserStateComplete *kSBJsonStreamParserStateComplete; - -SBJsonStreamParserStateObjectStart *kSBJsonStreamParserStateObjectStart; -static SBJsonStreamParserStateObjectGotKey *kSBJsonStreamParserStateObjectGotKey; -static SBJsonStreamParserStateObjectSeparator *kSBJsonStreamParserStateObjectSeparator; -static SBJsonStreamParserStateObjectGotValue *kSBJsonStreamParserStateObjectGotValue; -static SBJsonStreamParserStateObjectNeedKey *kSBJsonStreamParserStateObjectNeedKey; - -SBJsonStreamParserStateArrayStart *kSBJsonStreamParserStateArrayStart; -static SBJsonStreamParserState *kSBJsonStreamParserStateArrayGotValue; -static SBJsonStreamParserState *kSBJsonStreamParserStateArrayNeedValue; - -@implementation SBJsonStreamParserState - -- (BOOL)parser:(SBJsonStreamParser*)parser shouldAcceptToken:(sbjson_token_t)token { - return NO; -} - -- (BOOL)parserShouldStop:(SBJsonStreamParser*)parser { - return NO; -} - -- (SBJsonStreamParserStatus)parserShouldReturn:(SBJsonStreamParser*)parser { - return SBJsonStreamParserWaitingForData; -} - -- (void)parser:(SBJsonStreamParser*)parser shouldTransitionTo:(sbjson_token_t)tok {} - -- (BOOL)needKey { - return NO; -} - -- (NSString*)name { - return @""; -} - -@end - -#pragma mark - - -@implementation SBJsonStreamParserStateStart - -+ (id)sharedInstance { - if (!kSBJsonStreamParserStateStart) { - kSBJsonStreamParserStateStart = [[SBJsonStreamParserStateStart alloc] init]; - kSBJsonStreamParserStateError = [[SBJsonStreamParserStateError alloc] init]; - kSBJsonStreamParserStateComplete = [[SBJsonStreamParserStateComplete alloc] init]; - kSBJsonStreamParserStateObjectStart = [[SBJsonStreamParserStateObjectStart alloc] init]; - kSBJsonStreamParserStateObjectGotKey = [[SBJsonStreamParserStateObjectGotKey alloc] init]; - kSBJsonStreamParserStateObjectSeparator = [[SBJsonStreamParserStateObjectSeparator alloc] init]; - kSBJsonStreamParserStateObjectGotValue = [[SBJsonStreamParserStateObjectGotValue alloc] init]; - kSBJsonStreamParserStateObjectNeedKey = [[SBJsonStreamParserStateObjectNeedKey alloc] init]; - kSBJsonStreamParserStateArrayStart = [[SBJsonStreamParserStateArrayStart alloc] init]; - kSBJsonStreamParserStateArrayGotValue = [[SBJsonStreamParserStateArrayGotValue alloc] init]; - kSBJsonStreamParserStateArrayNeedValue = [[SBJsonStreamParserStateArrayNeedValue alloc] init]; - } - return kSBJsonStreamParserStateStart; -} - -- (BOOL)parser:(SBJsonStreamParser*)parser shouldAcceptToken:(sbjson_token_t)token { - return token == sbjson_token_array_start || token == sbjson_token_object_start; -} - -- (void)parser:(SBJsonStreamParser*)parser shouldTransitionTo:(sbjson_token_t)tok { - - SBJsonStreamParserState *state = nil; - switch (tok) { - case sbjson_token_array_start: - state = kSBJsonStreamParserStateArrayStart; - break; - - case sbjson_token_object_start: - state = kSBJsonStreamParserStateObjectStart; - break; - - case sbjson_token_array_end: - case sbjson_token_object_end: - if (parser.multi) - state = parser.states[parser.depth]; - else - state = kSBJsonStreamParserStateComplete; - break; - - case sbjson_token_eof: - return; - - default: - state = kSBJsonStreamParserStateError; - break; - } - - - parser.states[parser.depth] = state; -} - -- (NSString*)name { return @"before outer-most array or object"; } - -@end - -#pragma mark - - -@implementation SBJsonStreamParserStateComplete - -- (NSString*)name { return @"after outer-most array or object"; } - -- (BOOL)parserShouldStop:(SBJsonStreamParser*)parser { - return YES; -} - -- (SBJsonStreamParserStatus)parserShouldReturn:(SBJsonStreamParser*)parser { - return SBJsonStreamParserComplete; -} - -@end - -#pragma mark - - -@implementation SBJsonStreamParserStateError - -- (NSString*)name { return @"in error"; } - -- (BOOL)parserShouldStop:(SBJsonStreamParser*)parser { - return YES; -} - -- (SBJsonStreamParserStatus)parserShouldReturn:(SBJsonStreamParser*)parser { - return SBJsonStreamParserError; -} - -@end - -#pragma mark - - -@implementation SBJsonStreamParserStateObjectStart - -- (NSString*)name { return @"at beginning of object"; } - -- (BOOL)parser:(SBJsonStreamParser*)parser shouldAcceptToken:(sbjson_token_t)token { - switch (token) { - case sbjson_token_object_end: - case sbjson_token_string: - case sbjson_token_string_encoded: - return YES; - break; - default: - return NO; - break; - } -} - -- (void)parser:(SBJsonStreamParser*)parser shouldTransitionTo:(sbjson_token_t)tok { - parser.states[parser.depth] = kSBJsonStreamParserStateObjectGotKey; -} - -- (BOOL)needKey { - return YES; -} - -@end - -#pragma mark - - -@implementation SBJsonStreamParserStateObjectGotKey - -- (NSString*)name { return @"after object key"; } - -- (BOOL)parser:(SBJsonStreamParser*)parser shouldAcceptToken:(sbjson_token_t)token { - return token == sbjson_token_key_value_separator; -} - -- (void)parser:(SBJsonStreamParser*)parser shouldTransitionTo:(sbjson_token_t)tok { - parser.states[parser.depth] = kSBJsonStreamParserStateObjectSeparator; -} - -@end - -#pragma mark - - -@implementation SBJsonStreamParserStateObjectSeparator - -- (NSString*)name { return @"as object value"; } - -- (BOOL)parser:(SBJsonStreamParser*)parser shouldAcceptToken:(sbjson_token_t)token { - switch (token) { - case sbjson_token_object_start: - case sbjson_token_array_start: - case sbjson_token_true: - case sbjson_token_false: - case sbjson_token_null: - case sbjson_token_integer: - case sbjson_token_double: - case sbjson_token_string: - case sbjson_token_string_encoded: - return YES; - break; - - default: - return NO; - break; - } -} - -- (void)parser:(SBJsonStreamParser*)parser shouldTransitionTo:(sbjson_token_t)tok { - parser.states[parser.depth] = kSBJsonStreamParserStateObjectGotValue; -} - -@end - -#pragma mark - - -@implementation SBJsonStreamParserStateObjectGotValue - -- (NSString*)name { return @"after object value"; } - -- (BOOL)parser:(SBJsonStreamParser*)parser shouldAcceptToken:(sbjson_token_t)token { - switch (token) { - case sbjson_token_object_end: - case sbjson_token_separator: - return YES; - break; - default: - return NO; - break; - } -} - -- (void)parser:(SBJsonStreamParser*)parser shouldTransitionTo:(sbjson_token_t)tok { - parser.states[parser.depth] = kSBJsonStreamParserStateObjectNeedKey; -} - - -@end - -#pragma mark - - -@implementation SBJsonStreamParserStateObjectNeedKey - -- (NSString*)name { return @"in place of object key"; } - -- (BOOL)parser:(SBJsonStreamParser*)parser shouldAcceptToken:(sbjson_token_t)token { - switch (token) { - case sbjson_token_string: - case sbjson_token_string_encoded: - return YES; - break; - default: - return NO; - break; - } -} - -- (void)parser:(SBJsonStreamParser*)parser shouldTransitionTo:(sbjson_token_t)tok { - parser.states[parser.depth] = kSBJsonStreamParserStateObjectGotKey; -} - -- (BOOL)needKey { - return YES; -} - -@end - -#pragma mark - - -@implementation SBJsonStreamParserStateArrayStart - -- (NSString*)name { return @"at array start"; } - -- (BOOL)parser:(SBJsonStreamParser*)parser shouldAcceptToken:(sbjson_token_t)token { - switch (token) { - case sbjson_token_object_end: - case sbjson_token_key_value_separator: - case sbjson_token_separator: - return NO; - break; - - default: - return YES; - break; - } -} - -- (void)parser:(SBJsonStreamParser*)parser shouldTransitionTo:(sbjson_token_t)tok { - parser.states[parser.depth] = kSBJsonStreamParserStateArrayGotValue; -} - -@end - -#pragma mark - - -@implementation SBJsonStreamParserStateArrayGotValue - -- (NSString*)name { return @"after array value"; } - - -- (BOOL)parser:(SBJsonStreamParser*)parser shouldAcceptToken:(sbjson_token_t)token { - return token == sbjson_token_array_end || token == sbjson_token_separator; -} - -- (void)parser:(SBJsonStreamParser*)parser shouldTransitionTo:(sbjson_token_t)tok { - if (tok == sbjson_token_separator) - parser.states[parser.depth] = kSBJsonStreamParserStateArrayNeedValue; -} - -@end - -#pragma mark - - -@implementation SBJsonStreamParserStateArrayNeedValue - -- (NSString*)name { return @"as array value"; } - - -- (BOOL)parser:(SBJsonStreamParser*)parser shouldAcceptToken:(sbjson_token_t)token { - switch (token) { - case sbjson_token_array_end: - case sbjson_token_key_value_separator: - case sbjson_token_object_end: - case sbjson_token_separator: - return NO; - break; - - default: - return YES; - break; - } -} - -- (void)parser:(SBJsonStreamParser*)parser shouldTransitionTo:(sbjson_token_t)tok { - parser.states[parser.depth] = kSBJsonStreamParserStateArrayGotValue; -} - -@end - diff --git a/BitTicker/SBJsonStreamWriter.h b/BitTicker/SBJsonStreamWriter.h deleted file mode 100755 index b7a0372..0000000 --- a/BitTicker/SBJsonStreamWriter.h +++ /dev/null @@ -1,163 +0,0 @@ -/* - Copyright (c) 2010, Stig Brautaset. - 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 the the author nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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. - */ - -#import - -/// Enable JSON writing for non-native objects -@interface NSObject (SBProxyForJson) - -/** - @brief Allows generation of JSON for otherwise unsupported classes. - - If you have a custom class that you want to create a JSON representation for you can implement this method in your class. It should return a representation of your object defined in terms of objects that can be translated into JSON. For example, a Person object might implement it like this: - - @code - - (id)proxyForJson { - return [NSDictionary dictionaryWithObjectsAndKeys: - name, @"name", - phone, @"phone", - email, @"email", - nil]; - } - @endcode - - */ -- (id)proxyForJson; - -@end - -@class SBJsonStreamWriterState; - -/** - @brief The Stream Writer class. - - Accepts a stream of messages and writes JSON of these to an internal data object. At any time you can retrieve the amount of data up to now, for example if you want to start sending data to a file before you're finished generating the JSON. - - A range of high-, mid- and low-level methods. You can mix and match calls to these. For example, you may want to call -writeArrayOpen to start an array and then repeatedly call -writeObject: with an object. - - In JSON the keys of an object must be strings. NSDictionary keys need not be, but attempting to convert an NSDictionary with non-string keys into JSON will result in an error. - - NSNumber instances created with the +initWithBool: method are converted into the JSON boolean "true" and "false" values, and vice versa. Any other NSNumber instances are converted to a JSON number the way you would expect. - - */ - -@interface SBJsonStreamWriter : NSObject { - NSString *error; - SBJsonStreamWriterState **states; - NSMutableData *data; - NSUInteger depth, maxDepth; - BOOL sortKeys, humanReadable; -} - -/** - @brief The data written to the stream so far. - - This is a mutable object. This means that you can write a chunk of its - contents to an NSOutputStream, then chop as many bytes as you wrote off - the beginning of the buffer. - */ -@property(readonly) NSMutableData *data; - -@property(readonly) NSObject **states; -@property(readonly) NSUInteger depth; - -/** - @brief The maximum recursing depth. - - Defaults to 512. If the input is nested deeper than this the input will be deemed to be - malicious and the parser returns nil, signalling an error. ("Nested too deep".) You can - turn off this security feature by setting the maxDepth value to 0. - */ -@property NSUInteger maxDepth; - -/** - @brief Whether we are generating human-readable (multiline) JSON. - - Set whether or not to generate human-readable JSON. The default is NO, which produces - JSON without any whitespace between tokens. If set to YES, generates human-readable - JSON with linebreaks after each array value and dictionary key/value pair, indented two - spaces per nesting level. - */ -@property BOOL humanReadable; - -/** - @brief Whether or not to sort the dictionary keys in the output. - - If this is set to YES, the dictionary keys in the JSON output will be in sorted order. - (This is useful if you need to compare two structures, for example.) The default is NO. - */ -@property BOOL sortKeys; - -/** - @brief Contains the error description after an error has occured. - */ -@property (copy) NSString *error; - -/** @brief Write an NSDictionary to the JSON stream. - */ -- (BOOL)writeObject:(NSDictionary*)dict; - -/** - @brief Write an NSArray to the JSON stream. - */ -- (BOOL)writeArray:(NSArray *)array; - -/// Start writing an Object to the stream -- (BOOL)writeObjectOpen; - -/// Close the current object being written -- (BOOL)writeObjectClose; - -/// Start writing an Array to the stream -- (BOOL)writeArrayOpen; - -/// Close the current Array being written -- (BOOL)writeArrayClose; - -/// Write a null to the stream -- (BOOL)writeNull; - -/// Write a boolean to the stream -- (BOOL)writeBool:(BOOL)x; - -/// Write a Number to the stream -- (BOOL)writeNumber:(NSNumber*)n; - -/// Write a String to the stream -- (BOOL)writeString:(NSString*)s; - -@end - -@interface SBJsonStreamWriter (Private) -- (BOOL)writeValue:(id)v; -@end - diff --git a/BitTicker/SBJsonStreamWriter.m b/BitTicker/SBJsonStreamWriter.m deleted file mode 100755 index 1ac124f..0000000 --- a/BitTicker/SBJsonStreamWriter.m +++ /dev/null @@ -1,372 +0,0 @@ -/* - Copyright (c) 2010, Stig Brautaset. - 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 the the author nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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. - */ - -#import "SBJsonStreamWriter.h" -#import "SBJsonStreamWriterState.h" - -static NSMutableDictionary *stringCache; -static NSDecimalNumber *notANumber; - -@implementation SBJsonStreamWriter - -@synthesize error; -@dynamic depth; -@dynamic maxDepth; -@synthesize states; -@synthesize humanReadable; -@synthesize sortKeys; - -+ (void)initialize { - notANumber = [NSDecimalNumber notANumber]; - stringCache = [NSMutableDictionary new]; -} - -#pragma mark Housekeeping - -- (id)init { - self = [super init]; - if (self) { - data = [[NSMutableData alloc] initWithCapacity:1024u]; - maxDepth = 512; - states = calloc(maxDepth, sizeof(SBJsonStreamWriterState*)); - NSAssert(states, @"States not initialised"); - - states[0] = [SBJsonStreamWriterStateStart sharedInstance]; - } - return self; -} - -- (void)dealloc { - self.error = nil; - free(states); - [data release]; - [super dealloc]; -} - -#pragma mark Methods - -- (BOOL)writeObject:(NSDictionary *)dict { - if (![self writeObjectOpen]) - return NO; - - NSArray *keys = [dict allKeys]; - if (sortKeys) - keys = [keys sortedArrayUsingSelector:@selector(compare:)]; - - for (id k in keys) { - if (![k isKindOfClass:[NSString class]]) { - self.error = [NSString stringWithFormat:@"JSON object key must be string: %@", k]; - return NO; - } - - if (![self writeString:k]) - return NO; - if (![self writeValue:[dict objectForKey:k]]) - return NO; - } - - return [self writeObjectClose]; -} - -- (BOOL)writeArray:(NSArray*)array { - if (![self writeArrayOpen]) - return NO; - for (id v in array) - if (![self writeValue:v]) - return NO; - return [self writeArrayClose]; -} - - -- (BOOL)writeObjectOpen { - SBJsonStreamWriterState *s = states[depth]; - if ([s isInvalidState:self]) return NO; - if ([s expectingKey:self]) return NO; - [s appendSeparator:self]; - if (humanReadable && depth) [s appendWhitespace:self]; - - if (maxDepth && ++depth > maxDepth) { - self.error = @"Nested too deep"; - return NO; - } - - states[depth] = kSBJsonStreamWriterStateObjectStart; - [data appendBytes:"{" length:1]; - return YES; -} - -- (BOOL)writeObjectClose { - SBJsonStreamWriterState *state = states[depth--]; - if ([state isInvalidState:self]) return NO; - if (humanReadable) [state appendWhitespace:self]; - [data appendBytes:"}" length:1]; - [states[depth] transitionState:self]; - return YES; -} - -- (BOOL)writeArrayOpen { - SBJsonStreamWriterState *s = states[depth]; - if ([s isInvalidState:self]) return NO; - if ([s expectingKey:self]) return NO; - [s appendSeparator:self]; - if (humanReadable && depth) [s appendWhitespace:self]; - - if (maxDepth && ++depth > maxDepth) { - self.error = @"Nested too deep"; - return NO; - } - - states[depth] = kSBJsonStreamWriterStateArrayStart; - [data appendBytes:"[" length:1]; - return YES; -} - -- (BOOL)writeArrayClose { - SBJsonStreamWriterState *state = states[depth--]; - if ([state isInvalidState:self]) return NO; - if ([state expectingKey:self]) return NO; - if (humanReadable) [state appendWhitespace:self]; - - [data appendBytes:"]" length:1]; - [states[depth] transitionState:self]; - return YES; -} - -- (BOOL)writeNull { - SBJsonStreamWriterState *s = states[depth]; - if ([s isInvalidState:self]) return NO; - if ([s expectingKey:self]) return NO; - [s appendSeparator:self]; - if (humanReadable) [s appendWhitespace:self]; - - [data appendBytes:"null" length:4]; - [s transitionState:self]; - return YES; -} - -- (BOOL)writeBool:(BOOL)x { - SBJsonStreamWriterState *s = states[depth]; - if ([s isInvalidState:self]) return NO; - if ([s expectingKey:self]) return NO; - [s appendSeparator:self]; - if (humanReadable) [s appendWhitespace:self]; - - if (x) - [data appendBytes:"true" length:4]; - else - [data appendBytes:"false" length:5]; - [s transitionState:self]; - return YES; -} - - -- (BOOL)writeValue:(id)o { - if ([o isKindOfClass:[NSDictionary class]]) { - return [self writeObject:o]; - - } else if ([o isKindOfClass:[NSArray class]]) { - return [self writeArray:o]; - - } else if ([o isKindOfClass:[NSString class]]) { - [self writeString:o]; - return YES; - - } else if ([o isKindOfClass:[NSNumber class]]) { - return [self writeNumber:o]; - - } else if ([o isKindOfClass:[NSNull class]]) { - return [self writeNull]; - - } else if ([o respondsToSelector:@selector(proxyForJson)]) { - return [self writeValue:[o proxyForJson]]; - - } - - self.error = [NSString stringWithFormat:@"JSON serialisation not supported for %@", [o class]]; - return NO; -} - -static const char *strForChar(int c) { - switch (c) { - case 0: return "\\u0000"; break; - case 1: return "\\u0001"; break; - case 2: return "\\u0002"; break; - case 3: return "\\u0003"; break; - case 4: return "\\u0004"; break; - case 5: return "\\u0005"; break; - case 6: return "\\u0006"; break; - case 7: return "\\u0007"; break; - case 8: return "\\b"; break; - case 9: return "\\t"; break; - case 10: return "\\n"; break; - case 11: return "\\u000b"; break; - case 12: return "\\f"; break; - case 13: return "\\r"; break; - case 14: return "\\u000e"; break; - case 15: return "\\u000f"; break; - case 16: return "\\u0010"; break; - case 17: return "\\u0011"; break; - case 18: return "\\u0012"; break; - case 19: return "\\u0013"; break; - case 20: return "\\u0014"; break; - case 21: return "\\u0015"; break; - case 22: return "\\u0016"; break; - case 23: return "\\u0017"; break; - case 24: return "\\u0018"; break; - case 25: return "\\u0019"; break; - case 26: return "\\u001a"; break; - case 27: return "\\u001b"; break; - case 28: return "\\u001c"; break; - case 29: return "\\u001d"; break; - case 30: return "\\u001e"; break; - case 31: return "\\u001f"; break; - case 34: return "\\\""; break; - case 92: return "\\\\"; break; - } - NSLog(@"FUTFUTFUT: -->'%c'<---", c); - return "FUTFUTFUT"; -} - -- (BOOL)writeString:(NSString*)string { - SBJsonStreamWriterState *s = states[depth]; - if ([s isInvalidState:self]) return NO; - [s appendSeparator:self]; - if (humanReadable) [s appendWhitespace:self]; - - NSMutableData *buf = [stringCache objectForKey:string]; - if (buf) { - [data appendBytes:[buf bytes] length:[buf length]]; - [s transitionState:self]; - return YES; - } - - NSUInteger len = [string lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; - const char *utf8 = [string UTF8String]; - NSUInteger written = 0, i = 0; - - buf = [NSMutableData dataWithCapacity:len * 1.1f]; - [buf appendBytes:"\"" length:1]; - - for (i = 0; i < len; i++) { - int c = utf8[i]; - BOOL isControlChar = c >= 0 && c < 32; - if (isControlChar || c == '"' || c == '\\') { - if (i - written) - [buf appendBytes:utf8 + written length:i - written]; - written = i + 1; - - const char *t = strForChar(c); - [buf appendBytes:t length:strlen(t)]; - } - } - - if (i - written) - [buf appendBytes:utf8 + written length:i - written]; - - [buf appendBytes:"\"" length:1]; - [data appendBytes:[buf bytes] length:[buf length]]; - [stringCache setObject:buf forKey:string]; - [s transitionState:self]; - return YES; -} - -- (BOOL)writeNumber:(NSNumber*)number { - if ((CFBooleanRef)number == kCFBooleanTrue || (CFBooleanRef)number == kCFBooleanFalse) - return [self writeBool:[number boolValue]]; - - SBJsonStreamWriterState *s = states[depth]; - if ([s isInvalidState:self]) return NO; - if ([s expectingKey:self]) return NO; - [s appendSeparator:self]; - if (humanReadable) [s appendWhitespace:self]; - - if ((CFNumberRef)number == kCFNumberPositiveInfinity) { - self.error = @"+Infinity is not a valid number in JSON"; - return NO; - - } else if ((CFNumberRef)number == kCFNumberNegativeInfinity) { - self.error = @"-Infinity is not a valid number in JSON"; - return NO; - - } else if ((CFNumberRef)number == kCFNumberNaN) { - self.error = @"NaN is not a valid number in JSON"; - return NO; - - } else if (number == notANumber) { - self.error = @"NaN is not a valid number in JSON"; - return NO; - } - - const char *objcType = [number objCType]; - char num[64]; - size_t len; - - switch (objcType[0]) { - case 'c': case 'i': case 's': case 'l': case 'q': - len = sprintf(num, "%lld", [number longLongValue]); - break; - case 'C': case 'I': case 'S': case 'L': case 'Q': - len = sprintf(num, "%llu", [number unsignedLongLongValue]); - break; - case 'f': case 'd': default: - if ([number isKindOfClass:[NSDecimalNumber class]]) { - char const *utf8 = [[number stringValue] UTF8String]; - [data appendBytes:utf8 length: strlen(utf8)]; - [s transitionState:self]; - return YES; - } - len = sprintf(num, "%g", [number doubleValue]); - break; - } - [data appendBytes:num length: len]; - [s transitionState:self]; - return YES; -} - -#pragma mark Private methods - -- (NSUInteger)depth { - return depth; -} - -- (void)setMaxDepth:(NSUInteger)x { - NSAssert(x, @"maxDepth must be greater than 0"); - maxDepth = x; - states = realloc(states, x); - NSAssert(states, @"Failed to reallocate more memory for states"); -} - -- (NSMutableData*)data { - return data; -} - -@end diff --git a/BitTicker/SBJsonStreamWriterState.h b/BitTicker/SBJsonStreamWriterState.h deleted file mode 100755 index 23310ab..0000000 --- a/BitTicker/SBJsonStreamWriterState.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - Copyright (c) 2010, Stig Brautaset. - 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 the the author nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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. - */ - -#import - -@class SBJsonStreamWriter; - -@interface SBJsonStreamWriterState : NSObject -- (BOOL)isInvalidState:(SBJsonStreamWriter*)writer; -- (void)appendSeparator:(SBJsonStreamWriter*)writer; -- (BOOL)expectingKey:(SBJsonStreamWriter*)writer; -- (void)transitionState:(SBJsonStreamWriter*)writer; -- (void)appendWhitespace:(SBJsonStreamWriter*)writer; -@end - -@interface SBJsonStreamWriterStateObjectStart : SBJsonStreamWriterState -@end - -@interface SBJsonStreamWriterStateObjectKey : SBJsonStreamWriterStateObjectStart -@end - -@interface SBJsonStreamWriterStateObjectValue : SBJsonStreamWriterState -@end - -@interface SBJsonStreamWriterStateArrayStart : SBJsonStreamWriterState -@end - -@interface SBJsonStreamWriterStateArrayValue : SBJsonStreamWriterState -@end - -@interface SBJsonStreamWriterStateStart : SBJsonStreamWriterState -+ (id)sharedInstance; -@end - -@interface SBJsonStreamWriterStateComplete : SBJsonStreamWriterState -@end - -@interface SBJsonStreamWriterStateError : SBJsonStreamWriterState -@end - -extern SBJsonStreamWriterStateStart *kSBJsonStreamWriterStateStart; -extern SBJsonStreamWriterStateComplete *kSBJsonStreamWriterStateComplete; -extern SBJsonStreamWriterStateError *kSBJsonStreamWriterStateError; -extern SBJsonStreamWriterStateObjectStart *kSBJsonStreamWriterStateObjectStart; -extern SBJsonStreamWriterStateArrayStart *kSBJsonStreamWriterStateArrayStart; - diff --git a/BitTicker/SBJsonStreamWriterState.m b/BitTicker/SBJsonStreamWriterState.m deleted file mode 100755 index 711efa0..0000000 --- a/BitTicker/SBJsonStreamWriterState.m +++ /dev/null @@ -1,132 +0,0 @@ -/* - Copyright (c) 2010, Stig Brautaset. - 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 the the author nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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. - */ - -#import "SBJsonStreamWriterState.h" -#import "SBJsonStreamWriter.h" - -// States -SBJsonStreamWriterStateStart *kSBJsonStreamWriterStateStart; -SBJsonStreamWriterStateComplete *kSBJsonStreamWriterStateComplete; -SBJsonStreamWriterStateError *kSBJsonStreamWriterStateError; - -SBJsonStreamWriterStateObjectStart *kSBJsonStreamWriterStateObjectStart; -static SBJsonStreamWriterStateObjectKey *kSBJsonStreamWriterStateObjectKey; -static SBJsonStreamWriterStateObjectValue *kSBJsonStreamWriterStateObjectValue; - -SBJsonStreamWriterStateArrayStart *kSBJsonStreamWriterStateArrayStart; -static SBJsonStreamWriterStateArrayValue *kSBJsonStreamWriterStateArrayValue; - -@implementation SBJsonStreamWriterState -- (BOOL)isInvalidState:(SBJsonStreamWriter*)writer { return NO; } -- (void)appendSeparator:(SBJsonStreamWriter*)writer {} -- (BOOL)expectingKey:(SBJsonStreamWriter*)writer { return NO; } -- (void)transitionState:(SBJsonStreamWriter *)writer {} -- (void)appendWhitespace:(SBJsonStreamWriter*)writer { - [writer.data appendBytes:"\n" length:1]; - for (int i = 0; i < writer.depth; i++) - [writer.data appendBytes:" " length:2]; -} -@end - -@implementation SBJsonStreamWriterStateObjectStart -- (void)transitionState:(SBJsonStreamWriter *)writer { - writer.states[writer.depth] = kSBJsonStreamWriterStateObjectValue; -} -- (BOOL)expectingKey:(SBJsonStreamWriter *)writer { - writer.error = @"JSON object key must be string"; - return YES; -} -@end - -@implementation SBJsonStreamWriterStateObjectKey -- (void)appendSeparator:(SBJsonStreamWriter *)writer { - [writer.data appendBytes:"," length:1]; -} -@end - -@implementation SBJsonStreamWriterStateObjectValue -- (void)appendSeparator:(SBJsonStreamWriter *)writer { - [writer.data appendBytes:":" length:1]; -} -- (void)transitionState:(SBJsonStreamWriter *)writer { - writer.states[writer.depth] = kSBJsonStreamWriterStateObjectKey; -} -- (void)appendWhitespace:(SBJsonStreamWriter *)writer { - [writer.data appendBytes:" " length:1]; -} -@end - -@implementation SBJsonStreamWriterStateArrayStart -- (void)transitionState:(SBJsonStreamWriter *)writer { - writer.states[writer.depth] = kSBJsonStreamWriterStateArrayValue; -} -@end - -@implementation SBJsonStreamWriterStateArrayValue -- (void)appendSeparator:(SBJsonStreamWriter *)writer { - [writer.data appendBytes:"," length:1]; -} -@end - -@implementation SBJsonStreamWriterStateStart - -+ (id)sharedInstance { - if (!kSBJsonStreamWriterStateStart) { - kSBJsonStreamWriterStateStart = [SBJsonStreamWriterStateStart new]; - kSBJsonStreamWriterStateComplete = [SBJsonStreamWriterStateComplete new]; - kSBJsonStreamWriterStateError = [SBJsonStreamWriterStateError new]; - kSBJsonStreamWriterStateObjectStart = [SBJsonStreamWriterStateObjectStart new]; - kSBJsonStreamWriterStateObjectKey = [SBJsonStreamWriterStateObjectKey new]; - kSBJsonStreamWriterStateObjectValue = [SBJsonStreamWriterStateObjectValue new]; - kSBJsonStreamWriterStateArrayStart = [SBJsonStreamWriterStateArrayStart new]; - kSBJsonStreamWriterStateArrayValue = [SBJsonStreamWriterStateArrayValue new]; - } - return kSBJsonStreamWriterStateStart; -} - -- (void)transitionState:(SBJsonStreamWriter *)writer { - writer.states[writer.depth] = kSBJsonStreamWriterStateComplete; -} -- (void)appendSeparator:(SBJsonStreamWriter *)writer { -} -@end - -@implementation SBJsonStreamWriterStateComplete -- (BOOL)isInvalidState:(SBJsonStreamWriter*)writer { - writer.error = @"Stream is closed"; - return YES; -} -@end - -@implementation SBJsonStreamWriterStateError -@end - diff --git a/BitTicker/SBJsonTokeniser.h b/BitTicker/SBJsonTokeniser.h deleted file mode 100755 index f00cfcb..0000000 --- a/BitTicker/SBJsonTokeniser.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - Copyright (c) 2010, Stig Brautaset. - 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 the the author nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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. - */ - -#import - -typedef enum { - sbjson_token_eof, - sbjson_token_error, - sbjson_token_object_start, - sbjson_token_key_value_separator, - sbjson_token_object_end, - sbjson_token_array_start, - sbjson_token_array_end, - sbjson_token_separator, - sbjson_token_string, - sbjson_token_string_encoded, - sbjson_token_integer, - sbjson_token_double, - sbjson_token_true, - sbjson_token_false, - sbjson_token_null, -} sbjson_token_t; - -@interface SBJsonTokeniser : NSObject { - NSUInteger tokenStart, tokenLength; - NSMutableData *buf; - const char *bufbytes; - NSUInteger bufbytesLength; - NSString *error; -} - -@property(copy, readonly) NSString *error; - -- (void)appendData:(NSData*)data; - -- (sbjson_token_t)next; -- (BOOL)getToken:(const char **)utf8 length:(NSUInteger*)length; -- (NSString*)getDecodedStringToken; - -@end diff --git a/BitTicker/SBJsonTokeniser.m b/BitTicker/SBJsonTokeniser.m deleted file mode 100755 index 99ca8b0..0000000 --- a/BitTicker/SBJsonTokeniser.m +++ /dev/null @@ -1,476 +0,0 @@ -/* - Copyright (c) 2010, Stig Brautaset. - 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 the the author nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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. - */ - -#import "SBJsonTokeniser.h" - - -#define isDigit(x) (*x >= '0' && *x <= '9') -#define skipDigits(x) while (isDigit(x)) x++ - - -@interface SBJsonTokeniser () - -@property (copy) NSString *error; - -- (void)skipWhitespace; - -- (sbjson_token_t)match:(const char *)utf8 ofLength:(NSUInteger)len andReturn:(sbjson_token_t)tok; -- (sbjson_token_t)matchString; -- (sbjson_token_t)matchNumber; - -- (int)parseUnicodeEscape:(const char *)bytes index:(NSUInteger *)index; - -@end - - -@implementation SBJsonTokeniser - -@synthesize error; - -#pragma mark Housekeeping - -- (id)init { - self = [super init]; - if (self) { - tokenStart = tokenLength = 0; - buf = [[NSMutableData alloc] initWithCapacity:4096]; - } - return self; -} - -- (void)dealloc { - self.error = nil; - [buf release]; - [super dealloc]; -} - -#pragma mark Methods - -- (void)appendData:(NSData *)data { - - // Remove previous NUL char - if (buf.length) - buf.length = buf.length - 1; - - if (tokenStart) { - // Remove stuff in the front of the offset - [buf replaceBytesInRange:NSMakeRange(0, tokenStart) withBytes:"" length:0]; - tokenStart = 0; - } - - [buf appendData:data]; - - // Append NUL byte to simplify logic - [buf appendBytes:"\0" length:1]; - - bufbytes = [buf bytes]; - bufbytesLength = [buf length]; -} - -- (BOOL)getToken:(const char **)utf8 length:(NSUInteger *)len { - if (!tokenLength) - return NO; - - *len = tokenLength; - *utf8 = bufbytes + tokenStart; - return YES; -} - -- (NSString*)getDecodedStringToken { - NSUInteger len; - const char *bytes; - [self getToken:&bytes length:&len]; - - len -= 1; - - NSMutableData *data = [NSMutableData dataWithCapacity:len * 1.1]; - - char c; - NSUInteger i = 1; -again: while (i < len) { - switch (c = bytes[i++]) { - case '\\': - switch (c = bytes[i++]) { - case '\\': - case '/': - case '"': - break; - - case 'b': - c = '\b'; - break; - - case 'n': - c = '\n'; - break; - - case 'r': - c = '\r'; - break; - - case 't': - c = '\t'; - break; - - case 'f': - c = '\f'; - break; - - case 'u': { - int hi = [self parseUnicodeEscape:bytes index:&i]; - if (hi < 0) - return nil; - - unichar ch = hi; - NSString *s = [NSString stringWithCharacters:&ch length:1]; - [data appendData:[s dataUsingEncoding:NSUTF8StringEncoding]]; - goto again; - break; - } - - default: - NSAssert(NO, @"Should never get here"); - break; - } - break; - - case 0 ... 0x1F: - self.error = @"Unescaped control chars"; - return nil; - break; - - default: - break; - } - [data appendBytes:&c length:1]; - } - - return [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]; -} - - -- (sbjson_token_t)next { - tokenStart += tokenLength; - tokenLength = 0; - - [self skipWhitespace]; - - switch (*(bufbytes + tokenStart)) { - case '\0': - return sbjson_token_eof; - break; - - case '[': - tokenLength = 1; - return sbjson_token_array_start; - break; - - case ']': - tokenLength = 1; - return sbjson_token_array_end; - break; - - case '{': - tokenLength = 1; - return sbjson_token_object_start; - break; - - case ':': - tokenLength = 1; - return sbjson_token_key_value_separator; - break; - - case '}': - tokenLength = 1; - return sbjson_token_object_end; - break; - - case ',': - tokenLength = 1; - return sbjson_token_separator; - break; - - case 'n': - return [self match:"null" ofLength:4 andReturn:sbjson_token_null]; - break; - - case 't': - return [self match:"true" ofLength:4 andReturn:sbjson_token_true]; - break; - - case 'f': - return [self match:"false" ofLength:5 andReturn:sbjson_token_false]; - break; - - case '"': - return [self matchString]; - break; - - case '-': - case '0' ... '9': - return [self matchNumber]; - break; - - case '+': - self.error = [NSString stringWithFormat:@"Leading + is illegal in numbers at offset %u", tokenStart]; - return sbjson_token_error; - break; - } - - self.error = [NSString stringWithFormat:@"Unrecognised leading character at offset %u", tokenStart]; - return sbjson_token_error; -} - -#pragma mark Private methods - -- (void)skipWhitespace { - while (tokenStart < bufbytesLength) { - switch (bufbytes[tokenStart]) { - case ' ': - case '\t': - case '\n': - case '\r': - case '\f': - case '\v': - tokenStart++; - break; - default: - return; - break; - } - } -} - -- (sbjson_token_t)match:(const char *)utf8 ofLength:(NSUInteger)len andReturn:(sbjson_token_t)tok { - if (buf.length - tokenStart - 1 < len) - return sbjson_token_eof; - - if (strncmp(bufbytes + tokenStart, utf8, len)) { - NSString *format = [NSString stringWithFormat:@"Expected '%%s' but found '%%.%us'.", len]; - self.error = [NSString stringWithFormat:format, utf8, bufbytes + tokenStart]; - return sbjson_token_error; - } - - tokenLength = len; - return tok; -} - - -- (int)decodeHexQuad:(const char *)hexQuad { - char c; - int ret = 0; - for (int i = 0; i < 4; i++) { - ret *= 16; - switch (c = hexQuad[i]) { - case '\0': - return -2; - break; - - case '0' ... '9': - ret += c - '0'; - break; - - case 'a' ... 'f': - ret += 10 + c - 'a'; - break; - - case 'A' ... 'F': - ret += 10 + c - 'A'; - break; - - default: - self.error = @"XXX illegal digit in hex char"; - return -1; - break; - } - } - return ret; -} - -- (int)parseUnicodeEscape:(const char *)bytes index:(NSUInteger *)index { - int hi = [self decodeHexQuad:bytes + *index]; - if (hi == -2) return -2; // EOF - if (hi < 0) { - self.error = @"Missing hex quad"; - return -1; - } - *index += 4; - - if (hi >= 0xd800) { // high surrogate char? - if (hi < 0xdc00) { // yes - expect a low char - int lo = -1; - if (bytes[(*index)++] == '\\' && bytes[(*index)++] == 'u') - lo = [self decodeHexQuad:bytes + *index]; - - if (lo < 0) { - self.error = @"Missing low character in surrogate pair"; - return -1; - } - *index += 4; - - if (lo < 0xdc00 || lo >= 0xdfff) { - self.error = @"Invalid low surrogate char"; - return -1; - } - - hi = (hi - 0xd800) * 0x400 + (lo - 0xdc00) + 0x10000; - - } else if (hi < 0xe000) { - self.error = @"Invalid high character in surrogate pair"; - return -1; - } - } - return hi; -} - - -- (sbjson_token_t)matchString { - sbjson_token_t ret = sbjson_token_string; - - const char *bytes = bufbytes + tokenStart; - NSUInteger idx = 1; - NSUInteger maxIdx = buf.length - 2 - tokenStart; - - while (idx <= maxIdx) { - switch (bytes[idx++]) { - case 0 ... 0x1F: - self.error = [NSString stringWithFormat:@"Unescaped control char 0x%0.2X", (int)bytes[idx-1]]; - return sbjson_token_error; - break; - - case '\\': - ret = sbjson_token_string_encoded; - - if (idx >= maxIdx) - return sbjson_token_eof; - - switch (bytes[idx++]) { - case 'b': - case 't': - case 'n': - case 'r': - case 'f': - case 'v': - case '"': - case '\\': - case '/': - // Valid escape sequence - break; - - case 'u': { - int ch = [self parseUnicodeEscape:bytes index:&idx]; - if (ch == -2) - return sbjson_token_eof; - if (ch == -1) - return sbjson_token_error; - break; - } - default: - self.error = [NSString stringWithFormat:@"Broken escape character at index %u in token starting at offset %u", idx-1, tokenStart]; - return sbjson_token_error; - break; - } - break; - - case '"': - tokenLength = idx; - return ret; - break; - - default: - // any other character - break; - } - } - - return sbjson_token_eof; -} - -- (sbjson_token_t)matchNumber { - - sbjson_token_t ret = sbjson_token_integer; - const char *c = bufbytes + tokenStart; - - if (*c == '-') { - c++; - if (!isDigit(c)) { - self.error = @"No digits after initial minus"; - return sbjson_token_error; - } - } - - if (*c == '0') { - c++; - if (isDigit(c)) { - self.error = [NSString stringWithFormat:@"Leading zero is illegal in number at offset %u", tokenStart]; - return sbjson_token_error; - } - } - - skipDigits(c); - - - if (*c == '.') { - ret = sbjson_token_double; - c++; - - if (!isDigit(c) && *c) { - self.error = [NSString stringWithFormat:@"No digits after decimal point at offset %u", tokenStart]; - return sbjson_token_error; - } - - skipDigits(c); - } - - if (*c == 'e' || *c == 'E') { - ret = sbjson_token_double; - c++; - - if (*c == '-' || *c == '+') - c++; - - if (!isDigit(c) && *c) { - self.error = [NSString stringWithFormat:@"No digits after exponent mark at offset %u", tokenStart]; - return sbjson_token_error; - } - - skipDigits(c); - } - - if (!*c) - return sbjson_token_eof; - - tokenLength = c - (bufbytes + tokenStart); - return ret; -} - -@end diff --git a/BitTicker/SBJsonWriter.h b/BitTicker/SBJsonWriter.h deleted file mode 100755 index 393b85f..0000000 --- a/BitTicker/SBJsonWriter.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - Copyright (C) 2009 Stig Brautaset. 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 the author nor the names of its contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 OWNER 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. - */ - -#import - -/** - @brief The JSON writer class. - - Objective-C types are mapped to JSON types in the following way: - - @li NSNull -> Null - @li NSString -> String - @li NSArray -> Array - @li NSDictionary -> Object - @li NSNumber (-initWithBool:) -> Boolean - @li NSNumber -> Number - - In JSON the keys of an object must be strings. NSDictionary keys need - not be, but attempting to convert an NSDictionary with non-string keys - into JSON will throw an exception. - - NSNumber instances created with the +initWithBool: method are - converted into the JSON boolean "true" and "false" values, and vice - versa. Any other NSNumber instances are converted to a JSON number the - way you would expect. - - */ -@interface SBJsonWriter : NSObject { - -@protected - NSString *error; - NSUInteger maxDepth; - -@private - BOOL sortKeys, humanReadable; -} - -/** - @brief The maximum recursing depth. - - Defaults to 512. If the input is nested deeper than this the input will be deemed to be - malicious and the parser returns nil, signalling an error. ("Nested too deep".) You can - turn off this security feature by setting the maxDepth value to 0. - */ -@property NSUInteger maxDepth; - -/** - @brief Return an error trace, or nil if there was no errors. - - Note that this method returns the trace of the last method that failed. - You need to check the return value of the call you're making to figure out - if the call actually failed, before you know call this method. - */ -@property(copy) NSString *error; - -/** - @brief Whether we are generating human-readable (multiline) JSON. - - Set whether or not to generate human-readable JSON. The default is NO, which produces - JSON without any whitespace. (Except inside strings.) If set to YES, generates human-readable - JSON with linebreaks after each array value and dictionary key/value pair, indented two - spaces per nesting level. - */ -@property BOOL humanReadable; - -/** - @brief Whether or not to sort the dictionary keys in the output. - - If this is set to YES, the dictionary keys in the JSON output will be in sorted order. - (This is useful if you need to compare two structures, for example.) The default is NO. - */ -@property BOOL sortKeys; - -/** - @brief Return JSON representation for the given object. - - Returns a string containing JSON representation of the passed in value, or nil on error. - If nil is returned and @p error is not NULL, @p *error can be interrogated to find the cause of the error. - - @param value any instance that can be represented as JSON text. - */ -- (NSString*)stringWithObject:(id)value; - -/** - @brief Return JSON representation for the given object. - - Returns an NSData object containing JSON represented as UTF8 text, or nil on error. - - @param value any instance that can be represented as JSON text. - */ -- (NSData*)dataWithObject:(id)value; - -/** - @brief Return JSON representation (or fragment) for the given object. - - Returns a string containing JSON representation of the passed in value, or nil on error. - If nil is returned and @p error is not NULL, @p *error can be interrogated to find the cause of the error. - - @param value any instance that can be represented as a JSON fragment - @param error pointer to object to be populated with NSError on failure - - */- (NSString*)stringWithObject:(id)value - error:(NSError**)error; - - -@end diff --git a/BitTicker/SBJsonWriter.m b/BitTicker/SBJsonWriter.m deleted file mode 100755 index 8321786..0000000 --- a/BitTicker/SBJsonWriter.m +++ /dev/null @@ -1,102 +0,0 @@ -/* - Copyright (C) 2009 Stig Brautaset. 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 the author nor the names of its contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 OWNER 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. - */ - -#import "SBJsonWriter.h" -#import "SBJsonStreamWriter.h" - -@implementation SBJsonWriter - -@synthesize sortKeys; -@synthesize humanReadable; - -@synthesize error; -@synthesize maxDepth; - -- (id)init { - self = [super init]; - if (self) - self.maxDepth = 512; - return self; -} - -- (void)dealloc { - [error release]; - [super dealloc]; -} - -- (NSString*)stringWithObject:(id)value { - NSData *data = [self dataWithObject:value]; - if (data) - return [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]; - return nil; -} - -- (NSString*)stringWithObject:(id)value error:(NSError**)error_ { - NSString *tmp = [self stringWithObject:value]; - if (tmp) - return tmp; - - if (error_) { - NSDictionary *ui = [NSDictionary dictionaryWithObjectsAndKeys:error, NSLocalizedDescriptionKey, nil]; - *error_ = [NSError errorWithDomain:@"org.brautaset.json.parser.ErrorDomain" code:0 userInfo:ui]; - } - - return nil; -} - -- (NSData*)dataWithObject:(id)object { - SBJsonStreamWriter *streamWriter = [[[SBJsonStreamWriter alloc] init] autorelease]; - streamWriter.sortKeys = self.sortKeys; - streamWriter.maxDepth = self.maxDepth; - streamWriter.humanReadable = self.humanReadable; - - BOOL ok = NO; - if ([object isKindOfClass:[NSDictionary class]]) - ok = [streamWriter writeObject:object]; - - else if ([object isKindOfClass:[NSArray class]]) - ok = [streamWriter writeArray:object]; - - else if ([object respondsToSelector:@selector(proxyForJson)]) - return [self dataWithObject:[object proxyForJson]]; - else { - self.error = @"Not valid type for JSON"; - return nil; - } - - if (ok) - return streamWriter.data; - - self.error = streamWriter.error; - return nil; -} - - - -@end diff --git a/BitTicker/StatusItemView.h b/BitTicker/StatusItemView.h old mode 100644 new mode 100755 index b84b62e..3c86a04 --- a/BitTicker/StatusItemView.h +++ b/BitTicker/StatusItemView.h @@ -1,32 +1,29 @@ /* - BitTicker is Copyright 2011 Stephen Oliver - http://github.com/mrsteveman1 + BitTicker is Copyright 2012 Stephen Oliver + http://github.com/infincia - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ +*/ #import @interface StatusItemView : NSView { NSStatusItem *statusItem; NSNumber *tickerValue; + NSNumber *previousTickerValue; + NSDate *lastUpdated; + NSTimer *colorTimer; + NSColor *flashColor; + NSColor *currentColor; BOOL isMenuVisible; + BOOL isAnimating; + BOOL firstTick; + NSNumberFormatter *currencyFormatter; } -@property (retain, nonatomic) NSStatusItem *statusItem; -@property (retain, nonatomic) NSNumber *tickerValue; +@property (strong) NSStatusItem *statusItem; +@property (strong) NSNumber *tickerValue; +@property (strong) NSNumber *previousTickerValue; +@property (strong) NSTimer *colorTimer; - (void)setTickerValue:(NSNumber *)value; diff --git a/BitTicker/StatusItemView.m b/BitTicker/StatusItemView.m old mode 100644 new mode 100755 index 16092a0..6e9bdea --- a/BitTicker/StatusItemView.m +++ b/BitTicker/StatusItemView.m @@ -1,21 +1,8 @@ /* - BitTicker is Copyright 2011 Stephen Oliver - http://github.com/mrsteveman1 + BitTicker is Copyright 2012 Stephen Oliver + http://github.com/infincia - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ +*/ #import "StatusItemView.h" #import @@ -23,10 +10,12 @@ #define StatusItemViewPaddingWidth 6 #define StatusItemViewPaddingHeight 3 #define StatusItemWidth 50 +#define ColorFadeFramerate 30.0 +#define ColorFadeDuration 1.0 @implementation StatusItemView -@synthesize statusItem; +@synthesize statusItem, previousTickerValue, colorTimer; - (void)drawRect:(NSRect)rect { // Draw status bar background, highlighted if menu is showing @@ -35,13 +24,13 @@ - (void)drawRect:(NSRect)rect { NSPoint point = NSMakePoint(1, 1); NSMutableDictionary *fontAttributes = [[NSMutableDictionary alloc] init]; - NSFont *font = [NSFont fontWithName:@"LucidaGrande" size:16]; + NSFont *font = [NSFont fontWithName:@"LucidaGrande-Bold" size:16]; + - NSColor *black = [NSColor blackColor]; NSColor *white = [NSColor whiteColor]; [fontAttributes setObject:font forKey:NSFontAttributeName]; - NSString *tickerPretty = [NSString stringWithFormat:@"$%0.2f",[tickerValue floatValue]]; + NSString *tickerPretty = [currencyFormatter stringFromNumber:tickerValue]; CGSize expected = [tickerPretty sizeWithAttributes:fontAttributes]; CGRect newFrame = self.frame; newFrame.size.width = expected.width + 5; @@ -54,33 +43,59 @@ - (void)drawRect:(NSRect)rect { [tickerPretty drawAtPoint:point withAttributes:fontAttributes]; } else { - [fontAttributes setObject:black forKey:NSForegroundColorAttributeName]; + NSColor *foreground_color; + if(isAnimating){ + NSTimeInterval duration = -1.0 * [lastUpdated timeIntervalSinceNow]; + double colorAlpha; + + if(duration >= ColorFadeDuration){ + [self.colorTimer invalidate]; + isAnimating = NO; + colorAlpha = 0.0; + } else { + colorAlpha = 1.0 - (duration / ColorFadeDuration); + } + + foreground_color = [currentColor blendedColorWithFraction:colorAlpha ofColor:flashColor]; + } + else foreground_color = currentColor; + + [fontAttributes setObject:foreground_color forKey:NSForegroundColorAttributeName]; [tickerPretty drawAtPoint:point withAttributes:fontAttributes]; } - - [fontAttributes release]; } - (id)initWithFrame:(NSRect)frame { CGRect newFrame = CGRectMake(0,0,StatusItemWidth,[[NSStatusBar systemStatusBar] thickness]); self = [super initWithFrame:newFrame]; - if (self) { - self.tickerValue = [NSNumber numberWithInt:0]; - statusItem = nil; - isMenuVisible = NO; - [statusItem setLength:StatusItemWidth]; - } - return self; -} + + firstTick = YES; + self.previousTickerValue = [NSNumber numberWithInt:0]; + self.tickerValue = [NSNumber numberWithInt:0]; + flashColor = [NSColor blackColor]; + currentColor = [NSColor blackColor]; + lastUpdated = [NSDate date]; + statusItem = nil; + isMenuVisible = NO; + isAnimating = NO; + [statusItem setLength:StatusItemWidth]; + + currencyFormatter = [[NSNumberFormatter alloc] init]; + currencyFormatter.numberStyle = NSNumberFormatterCurrencyStyle; + currencyFormatter.currencyCode = @"USD"; // TODO: Base on market currency + currencyFormatter.thousandSeparator = @","; // TODO: Base on local seperator for currency + currencyFormatter.alwaysShowsDecimalSeparator = YES; + currencyFormatter.hasThousandSeparators = YES; + currencyFormatter.minimumFractionDigits = 2; // TODO: Configurable + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveTicker:) name:@"MtGox-Ticker" object:nil]; -- (void)dealloc { - [statusItem release]; - [tickerValue release]; - [super dealloc]; + return self; } - (void)mouseDown:(NSEvent *)event { + NSLog(@"Menu click"); [[self menu] setDelegate:self]; [statusItem popUpStatusItemMenu:[self menu]]; [self setNeedsDisplay:YES]; @@ -111,11 +126,59 @@ - (NSColor *)ForegroundColor { } } +- (void)updateFade { + [self setNeedsDisplay:YES]; +} + - (void)setTickerValue:(NSNumber *)value { - [value retain]; - [tickerValue release]; + previousTickerValue = tickerValue; tickerValue = value; + BOOL animate_color = YES; + if(firstTick){ + firstTick = NO; + animate_color = NO; + } else if(tickerValue > previousTickerValue){ + + flashColor = [NSColor greenColor]; + + currentColor = [NSColor colorWithDeviceRed:0 green:0.55 blue:0 alpha:1.0]; + NSLog(@"Going green..."); + } else if(tickerValue < previousTickerValue){ + + flashColor = [NSColor redColor]; + + currentColor = [NSColor colorWithDeviceRed:0.55 green:0 blue:0 alpha:1.0]; + NSLog(@"Going red..."); + + } else { + animate_color = NO; + } + + if(animate_color){ + + self.colorTimer = [NSTimer scheduledTimerWithTimeInterval:(1.0/ColorFadeFramerate) + target:self + selector:@selector(updateFade) + userInfo:nil + repeats:YES]; + + lastUpdated = [NSDate date]; + isAnimating = YES; + } + + [self setNeedsDisplay:YES]; + + +} + +-(void)didReceiveTicker:(NSNotification *)notification { + NSDictionary *ticker = [[notification object] objectForKey:@"ticker"]; + + dispatch_async(dispatch_get_main_queue(), ^{ + [self setTickerValue:[ticker objectForKey:@"last"]]; + }); + } - (NSNumber *)tickerValue { diff --git a/BitTicker/TaggedNSURLConnection.h b/BitTicker/TaggedNSURLConnection.h deleted file mode 100644 index 9aed7f8..0000000 --- a/BitTicker/TaggedNSURLConnection.h +++ /dev/null @@ -1,17 +0,0 @@ -// -// TaggedNSUrlConnection.h -// Bitcoin Trader -// -// Created by Matt Stith on 4/30/11. -// Copyright 2011 Insomnia Addict. All rights reserved. -// -// NSURLConnection with an integer tag, for easier identification - -#import - - -@interface TaggedNSURLConnection : NSURLConnection { - NSInteger _tag; -} -@property (nonatomic) NSInteger tag; -@end diff --git a/BitTicker/TaggedNSURLConnection.m b/BitTicker/TaggedNSURLConnection.m deleted file mode 100644 index bb2d40f..0000000 --- a/BitTicker/TaggedNSURLConnection.m +++ /dev/null @@ -1,14 +0,0 @@ -// -// TaggedNSUrlConnection.m -// Bitcoin Trader -// -// Created by Matt Stith on 4/30/11. -// Copyright 2011 Insomnia Addict. All rights reserved. -// - -#import "TaggedNSURLConnection.h" - - -@implementation TaggedNSURLConnection -@synthesize tag=_tag; -@end diff --git a/BitTicker/Ticker.h b/BitTicker/Ticker.h deleted file mode 100644 index 6545a2d..0000000 --- a/BitTicker/Ticker.h +++ /dev/null @@ -1,26 +0,0 @@ -// -// Ticker.h -// Bitcoin Trader -// -// Created by Matt Stith on 4/30/11. -// Copyright 2011 Insomnia Addict. All rights reserved. -// - -#import - - -@interface Ticker : NSObject { - NSNumber *_high; - NSNumber *_low; - NSNumber *_volume; - NSNumber *_buy; - NSNumber *_sell; - NSNumber *_last; -} -@property (nonatomic, retain) NSNumber *high; -@property (nonatomic, retain) NSNumber *low; -@property (nonatomic, retain) NSNumber *volume; -@property (nonatomic, retain) NSNumber *buy; -@property (nonatomic, retain) NSNumber *sell; -@property (nonatomic, retain) NSNumber *last; -@end diff --git a/BitTicker/Ticker.m b/BitTicker/Ticker.m deleted file mode 100644 index b5244b6..0000000 --- a/BitTicker/Ticker.m +++ /dev/null @@ -1,24 +0,0 @@ -// -// Ticker.m -// Bitcoin Trader -// -// Created by Matt Stith on 4/30/11. -// Copyright 2011 Insomnia Addict. All rights reserved. -// - -#import "Ticker.h" - - -@implementation Ticker -@synthesize high=_high; -@synthesize low=_low; -@synthesize volume=_volume; -@synthesize buy=_buy; -@synthesize sell=_sell; -@synthesize last=_last; - --(NSString*)description { - return [NSString stringWithFormat:@"",_last, _high, _low, _volume]; -} - -@end diff --git a/BitTicker/Trade.h b/BitTicker/Trade.h deleted file mode 100644 index c99a81d..0000000 --- a/BitTicker/Trade.h +++ /dev/null @@ -1,24 +0,0 @@ -// -// Trade.h -// Bitcoin Trader -// -// Created by Matt Stith on 4/27/11. -// Copyright 2011 Insomnia Addict. All rights reserved. -// - -#import - - -@interface Trade : NSObject { - NSInteger _tid; // Trade ID - NSNumber *_price; // Price in USD - NSNumber *_amount; // Amount bought/sold in BTC - NSDate *_date; // Time/date that trade was fulfilled -} - -@property (nonatomic) NSInteger tid; -@property (nonatomic, retain) NSNumber *price; -@property (nonatomic, retain) NSNumber *amount; -@property (nonatomic, retain) NSDate *date; - -@end diff --git a/BitTicker/Trade.m b/BitTicker/Trade.m deleted file mode 100644 index d7a1516..0000000 --- a/BitTicker/Trade.m +++ /dev/null @@ -1,19 +0,0 @@ -// -// Trade.m -// Bitcoin Trader -// -// Created by Matt Stith on 4/27/11. -// Copyright 2011 Insomnia Addict. All rights reserved. -// - -#import "Trade.h" - - -@implementation Trade - -@synthesize tid=_tid; -@synthesize date=_date; -@synthesize price=_price; -@synthesize amount=_amount; - -@end diff --git a/BitTicker/en.lproj/InfoPlist.strings b/BitTicker/en.lproj/InfoPlist.strings old mode 100644 new mode 100755 index a48065a..1746d7e --- a/BitTicker/en.lproj/InfoPlist.strings +++ b/BitTicker/en.lproj/InfoPlist.strings @@ -1,18 +1,6 @@ /* - BitTicker is Copyright 2011 Stephen Oliver - http://github.com/mrsteveman1 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ + BitTicker is Copyright 2012 Stephen Oliver + http://github.com/infincia + + + */ \ No newline at end of file diff --git a/BitTicker/en.lproj/MainMenu.xib b/BitTicker/en.lproj/MainMenu.xib old mode 100644 new mode 100755 index a6ae037..7d6ffaa --- a/BitTicker/en.lproj/MainMenu.xib +++ b/BitTicker/en.lproj/MainMenu.xib @@ -1,40 +1,37 @@ - 1060 - 10J869 - 1306 - 1038.35 - 461.00 + 1070 + 11D50 + 2182 + 1138.32 + 568.00 com.apple.InterfaceBuilder.CocoaPlugin - 1306 + 2182 YES - NSComboBoxCell - NSMenuItem - NSMenu + NSSegmentedControl + NSButton + NSImageView NSTextFieldCell - NSSecureTextFieldCell - NSComboBox + NSButtonCell + NSBox + NSImageCell NSCustomObject - NSSecureTextField - NSView - NSWindowTemplate - NSTextField + NSCustomView NSUserDefaultsController + NSSegmentedCell + NSTextField YES com.apple.InterfaceBuilder.CocoaPlugin - YES - - YES - - + PluginDependencyRecalculationVersion + YES @@ -53,314 +50,469 @@ NSFontManager - - AMainMenu - + + YES + + + Dropdown + + + + 268 + YES - - - BitTicker - - 1048576 - 2147483647 - - NSImage - NSMenuCheckmark - - - NSImage - NSMenuMixedState - - submenuAction: - - BitTicker - + + + 268 + {{27, 220}, {278, 24}} + + + _NS:9 + YES + + 67239424 + 0 + + LucidaGrande + 13 + 16 + + _NS:9 + + YES - - - About BitTicker - - 2147483647 - - + + 96 + 30 Min + 0 - - - YES - YES - - - 1048576 - 2147483647 - - + + 12 Hours + 1 + YES + 0 - - - Quit BitTicker - q - 1048576 - 2147483647 - - + + 96 + 24 Hours + 0 - _NSAppleMenu + 1 + 1 - - _NSMainMenu - - - 4099 - 2 - {{196, 240}, {383, 166}} - 1618478080 - Settings - NSWindow - - - - 256 - - YES - - - 268 - {{60, 129}, {52, 17}} - - - - YES - - 68288064 - 272630784 - Market: - - LucidaGrande - 13 - 1044 - - - - 6 - System - controlColor - - 3 - MC42NjY2NjY2NjY3AA - + + + 268 + {{35, 14}, {111, 18}} + + + _NS:3944 + YES + + 67239488 + 272631872 + BitTicker + + LucidaGrande-Bold + 14 + 16 + + _NS:3944 + + + 6 + System + controlColor + + 3 + MC42NjY2NjY2NjY3AA - - 6 - System - controlTextColor - - 3 - MAA - + + + 6 + System + controlTextColor + + 3 + MAA - - - 268 - {{117, 123}, {249, 26}} - - - - YES - - 343014976 - 272630784 - - - - YES - - 6 - System - textBackgroundColor - - 3 - MQA - - - - 1 - YES - + + + + 12 + + YES + + + 274 + YES - MtGox - - - - - 274 - {13, 21} - - - YES - - YES - - 10 - 10 - 1000 - - 75628032 - 0 - - - LucidaGrande - 12 - 16 - - - 3 - MC4zMzMzMzI5ODU2AA - - + + + 268 + {{15, 114}, {38, 17}} + + + _NS:3944 + YES + + 68288064 + 272630784 + High: + + LucidaGrande + 13 + 1044 - - 338820672 - 1024 - - - YES - - 6 - System - controlBackgroundColor - - - + _NS:3944 + + + + + + + + 268 + {{132, 114}, {149, 17}} + + + _NS:3944 + YES + + 68288064 + 71304192 + Label + + _NS:3944 + + + + + + + + 268 + {{132, 89}, {149, 17}} + + + _NS:3944 + YES + + 68288064 + 71304192 + Label + + _NS:3944 + + + + + + + + 268 + {{15, 89}, {34, 17}} + + + _NS:3944 + YES + + 68288064 + 272630784 + Low: + + _NS:3944 + + + + + + + + 268 + {{15, 64}, {31, 17}} + + + _NS:3944 + YES + + 68288064 + 272630784 + Buy: + + _NS:3944 + + + + + + + + 268 + {{132, 64}, {149, 17}} + + + _NS:3944 + YES + + 68288064 + 71304192 + Label + + _NS:3944 + + + + + + + + 268 + {{15, 39}, {30, 17}} + + + _NS:3944 + YES + + 68288064 + 272630784 + Sell: + + _NS:3944 + + + + + + + + 268 + {{109, 39}, {172, 17}} + + + _NS:3944 + YES + + 68288064 + 71304192 + Label + + _NS:3944 + + + + + + + + 268 + {{15, 14}, {97, 17}} + + + _NS:3944 + YES + + 68288064 + 272630784 + Trade Volume: + + _NS:3944 + + + + + + + + 268 + {{109, 14}, {172, 17}} + + + _NS:3944 + YES + + 68288064 + 71304192 + Label + + _NS:3944 + + + + + + + + 268 + + YES + + YES + Apple PDF pasteboard type + Apple PICT pasteboard type + Apple PNG pasteboard type + NSFilenamesPboardType + NeXT Encapsulated PostScript v1.2 pasteboard type + NeXT TIFF v4.0 pasteboard type - 3 - YES - + {{15, -40}, {24, 24}} + + + _NS:2141 + YES + + 130560 + 33554432 + _NS:2141 + 0 + 0 + 0 + NO + + YES - 3 - 2 - - - 6 - System - gridColor - - 3 - MC41AA + + + 268 + {{44, -36}, {237, 17}} + + + _NS:3944 + YES + + 67239488 + 272631808 + + + + _NS:3944 + + + - 19 - tableViewAction: - -765427712 - - - - 1 - 15 - 0 - YES - 0 + {{1, 1}, {296, 148}} + + + _NS:21 - - - 268 - {{41, 77}, {71, 17}} - - - - YES - - 68288064 - 272630784 - Username: - - - - + {{17, 43}, {298, 164}} + + + _NS:18 + {0, 0} + + 67239424 + 0 + Trade data + + LucidaGrande + 11 + 3100 - - - - 268 - {{117, 74}, {246, 22}} - - - - YES - - -1804468671 - 272630784 - - - - YES - - - 6 - System - textColor - + + 6 + System + textBackgroundColor + + 3 + MQA - - - - 268 - {{44, 23}, {68, 17}} - - - - YES - - 68288064 - 272630784 - Password: - - - - + + 3 + MCAwLjgwMDAwMDAxMTkAA - - - 268 - {{117, 20}, {246, 22}} - - - - YES - - 343014976 - 272630848 - - - - YES - - - + + 1 + 0 + 2 + NO + + + + 12 + + YES + + + 274 + YES - NSAllRomanInputSourcesLocaleIdentifier + + + 268 + {{2, 3}, {292, 151}} + + + _NS:1192 + GraphView + + {{1, 1}, {296, 153}} + + + _NS:21 + + + {{17, 258}, {298, 169}} + + + _NS:18 + {0, 0} + + 67239424 + 0 + Last price + + + + 3 + MCAwLjgwMDAwMDAxMTkAA + + 1 + 0 + 2 + NO + + + + 268 + {{271, 12}, {41, 25}} + + + _NS:287 + YES + + -2080244224 + 134217728 + Quit + + _NS:287 + + -2038152961 + 163 + + + 400 + 75 + - {{7, 11}, {383, 166}} - - - - {{0, 0}, {1280, 778}} - {1e+13, 1e+13} - - - YES + {332, 435} + + + NSView @@ -374,105 +526,140 @@ 495 - - - orderFrontStandardAboutPanel: - - - - 685 - terminate: - - + + - 686 + 785 - - settings_window - - + + timeframeChanged: + + - 701 + 836 - - market_selector - - + + value: high + + + + + + value: high + value + high + 2 + - 702 + 820 - - username_field - - + + value: low + + + + + + value: low + value + low + 2 + - 703 + 823 - - password_field - - + + value: buy + + + + + + value: buy + value + buy + 2 + - 704 + 826 - value: self.password - - + value: sell + + - - - value: self.password + + + value: sell value - self.password + sell 2 - 713 + 829 - value: self.username - - + value: vol + + - - - value: self.username + + + value: vol value - self.username + vol 2 - 716 + 832 + + + + dropdownView + + + + 833 - value: self.selected_market - - + selectedIndex: values.timeframe + + - - - value: self.selected_market - value - self.selected_market + + + selectedIndex: values.timeframe + selectedIndex + values.timeframe - NSNullPlaceholder - MtGox + YES + + YES + NSNoSelectionPlaceholder + NSNotApplicablePlaceholder + NSNullPlaceholder + + + YES + + + + 2 - 718 + 841 @@ -480,7 +667,9 @@ YES 0 - + + YES + @@ -513,170 +702,275 @@ - 540 - + 705 + + + + + 745 + YES - + + + + + - 546 - + 748 + YES - + - + - 553 - + 749 + YES - - - + - + - 557 - - + 750 + + + YES + + + + + + + + + + + + + + - 561 - - - Menu Item - Quit BitTicker + 751 + + + YES + + + - 564 - - - Menu Item - About BitTicker + 752 + + + YES + + - 687 - + 753 + YES - + - - Settings Window + - 688 - + 754 + YES - - - - - - + - - Settings View + - 689 - + 755 + YES - + - - Markets + - 690 - + 756 + YES - + - - Password Label + - 691 - + 757 + YES - + - - Username Label + - 692 - + 758 + YES - + - + - 693 - + 759 + YES - + - - username_field + - 694 - + 760 + YES - + - - password_field + - 695 - - + 761 + + + YES + + + - 696 - - + 762 + + + YES + + + - 697 - - + 763 + + + YES + + + - 698 - - + 764 + + + YES + + + - 699 - - + 769 + + - 700 - - + 770 + + - 705 - + 771 + + + + + 772 + + + + + 773 + + + + + 774 + + + + + 775 + + + + + 776 + + + + + 777 + + + + + 778 + + + + + 779 + + + + + 780 + + + + + 781 + + + + + 782 + + + + + 817 + + + 834 + + + YES + + + + + + 835 + + + @@ -688,73 +982,58 @@ -3.IBPluginDependency 420.IBPluginDependency 494.IBPluginDependency - 540.IBEditorWindowLastContentRect - 540.IBPluginDependency - 540.ImportedFromIB2 - 540.WindowOrigin - 540.editorWindowContentRectSynchronizationRect - 546.IBPluginDependency - 546.ImportedFromIB2 - 553.IBEditorWindowLastContentRect - 553.IBPluginDependency - 553.ImportedFromIB2 - 553.editorWindowContentRectSynchronizationRect - 557.IBPluginDependency - 557.ImportedFromIB2 - 561.IBPluginDependency - 561.ImportedFromIB2 - 564.IBPluginDependency - 564.ImportedFromIB2 - 687.IBPluginDependency - 687.IBWindowTemplateEditedContentRect - 687.NSWindowTemplate.visibleAtLaunch - 687.WindowOrigin - 687.editorWindowContentRectSynchronizationRect - 688.IBPluginDependency - 689.IBPluginDependency - 690.IBPluginDependency - 691.IBPluginDependency - 692.IBPluginDependency - 693.IBPluginDependency - 694.IBPluginDependency - 695.IBPluginDependency - 696.IBPluginDependency - 697.IBPluginDependency - 698.IBPluginDependency - 699.IBPluginDependency - 700.IBComboBoxObjectValuesKey.objectValues - 700.IBPluginDependency 705.IBPluginDependency + 745.IBPluginDependency + 748.IBPluginDependency + 749.IBPluginDependency + 750.IBPluginDependency + 751.IBPluginDependency + 752.IBPluginDependency + 753.IBPluginDependency + 754.IBPluginDependency + 755.IBPluginDependency + 756.IBPluginDependency + 757.IBPluginDependency + 758.IBPluginDependency + 759.IBPluginDependency + 760.IBPluginDependency + 761.IBPluginDependency + 762.IBPluginDependency + 763.IBPluginDependency + 764.IBPluginDependency + 769.IBPluginDependency + 770.IBPluginDependency + 771.IBPluginDependency + 772.IBPluginDependency + 773.IBPluginDependency + 774.IBPluginDependency + 775.IBPluginDependency + 776.IBPluginDependency + 777.IBPluginDependency + 778.IBPluginDependency + 779.IBPluginDependency + 780.IBPluginDependency + 781.IBPluginDependency + 782.IBPluginDependency + 817.IBPluginDependency + 834.IBPluginDependency + 835.IBNSSegmentedControlInspectorSelectedSegmentMetadataKey + 835.IBPluginDependency - + YES com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - {{380, 836}, {512, 20}} com.apple.InterfaceBuilder.CocoaPlugin - - {74, 862} - {{6, 978}, {478, 20}} com.apple.InterfaceBuilder.CocoaPlugin - - {{286, 129}, {275, 183}} com.apple.InterfaceBuilder.CocoaPlugin - - {{23, 794}, {245, 183}} com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - {{357, 418}, {480, 270}} - - {196, 240} - {{357, 418}, {480, 270}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -767,12 +1046,24 @@ com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - - YES - MtGox - com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin @@ -787,102 +1078,16 @@ - 718 - - - - YES - - BitTickerAppDelegate - NSObject - - showSettings: - id - - - showSettings: - - showSettings: - id - - - - YES - - YES - market_selector - password_field - settings_window - username_field - - - YES - NSComboBox - NSSecureTextField - NSWindow - NSTextField - - - - YES - - YES - market_selector - password_field - settings_window - username_field - - - YES - - market_selector - NSComboBox - - - password_field - NSSecureTextField - - - settings_window - NSWindow - - - username_field - NSTextField - - - - - IBProjectSource - ./Classes/BitTickerAppDelegate.h - - - + 841 + 0 IBCocoaFramework - - com.apple.InterfaceBuilder.CocoaPlugin.macosx - - com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3 YES 3 - - YES - - YES - NSMenuCheckmark - NSMenuMixedState - - - YES - {9, 8} - {7, 2} - - diff --git a/BitTicker/main.m b/BitTicker/main.m old mode 100644 new mode 100755 index ee834c6..888eae9 --- a/BitTicker/main.m +++ b/BitTicker/main.m @@ -1,20 +1,8 @@ /* - BitTicker is Copyright 2011 Stephen Oliver - http://github.com/mrsteveman1 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + BitTicker is Copyright 2012 Stephen Oliver + http://github.com/infincia + + */ #import diff --git a/CorePlot.framework/CorePlot b/CorePlot.framework/CorePlot new file mode 120000 index 0000000..3937904 --- /dev/null +++ b/CorePlot.framework/CorePlot @@ -0,0 +1 @@ +Versions/Current/CorePlot \ No newline at end of file diff --git a/CorePlot.framework/Headers b/CorePlot.framework/Headers new file mode 120000 index 0000000..a177d2a --- /dev/null +++ b/CorePlot.framework/Headers @@ -0,0 +1 @@ +Versions/Current/Headers \ No newline at end of file diff --git a/CorePlot.framework/PrivateHeaders b/CorePlot.framework/PrivateHeaders new file mode 120000 index 0000000..d8e5645 --- /dev/null +++ b/CorePlot.framework/PrivateHeaders @@ -0,0 +1 @@ +Versions/Current/PrivateHeaders \ No newline at end of file diff --git a/CorePlot.framework/Resources b/CorePlot.framework/Resources new file mode 120000 index 0000000..953ee36 --- /dev/null +++ b/CorePlot.framework/Resources @@ -0,0 +1 @@ +Versions/Current/Resources \ No newline at end of file diff --git a/CorePlot.framework/Versions/A/CorePlot b/CorePlot.framework/Versions/A/CorePlot new file mode 100755 index 0000000..4ab7bf1 Binary files /dev/null and b/CorePlot.framework/Versions/A/CorePlot differ diff --git a/CorePlot.framework/Versions/A/Headers/CPTAnnotation.h b/CorePlot.framework/Versions/A/Headers/CPTAnnotation.h new file mode 100644 index 0000000..d6ae9b4 --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTAnnotation.h @@ -0,0 +1,34 @@ +#import "CPTDefinitions.h" +#import +#import + +@class CPTAnnotationHostLayer; +@class CPTLayer; + +@interface CPTAnnotation : NSObject { + @private + __cpt_weak CPTAnnotationHostLayer *annotationHostLayer; + CPTLayer *contentLayer; + CGPoint contentAnchorPoint; + CGPoint displacement; + CGFloat rotation; +} + +@property (nonatomic, readwrite, retain) CPTLayer *contentLayer; +@property (nonatomic, readwrite, cpt_weak_property) __cpt_weak CPTAnnotationHostLayer *annotationHostLayer; +@property (nonatomic, readwrite, assign) CGPoint contentAnchorPoint; +@property (nonatomic, readwrite, assign) CGPoint displacement; +@property (nonatomic, readwrite, assign) CGFloat rotation; + +@end + +#pragma mark - + +/** @category CPTAnnotation(AbstractMethods) + * @brief CPTAnnotation abstract methods—must be overridden by subclasses. + **/ +@interface CPTAnnotation(AbstractMethods) + +-(void)positionContentLayer; + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTAnnotationHostLayer.h b/CorePlot.framework/Versions/A/Headers/CPTAnnotationHostLayer.h new file mode 100644 index 0000000..841523d --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTAnnotationHostLayer.h @@ -0,0 +1,19 @@ +#import "CPTLayer.h" + +@class CPTAnnotation; + +@interface CPTAnnotationHostLayer : CPTLayer { + @private + NSMutableArray *mutableAnnotations; +} + +@property (nonatomic, readonly, retain) NSArray *annotations; + +/// @name Annotations +/// @{ +-(void)addAnnotation:(CPTAnnotation *)annotation; +-(void)removeAnnotation:(CPTAnnotation *)annotation; +-(void)removeAllAnnotations; +/// @} + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTAxis.h b/CorePlot.framework/Versions/A/Headers/CPTAxis.h new file mode 100644 index 0000000..fa1409f --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTAxis.h @@ -0,0 +1,265 @@ +#import "CPTDefinitions.h" +#import "CPTLayer.h" +#import "CPTTextStyle.h" +#import + +/// @file + +@class CPTAxis; +@class CPTAxisSet; +@class CPTAxisTitle; +@class CPTGridLines; +@class CPTLimitBand; +@class CPTLineCap; +@class CPTLineStyle; +@class CPTPlotSpace; +@class CPTPlotRange; +@class CPTPlotArea; +@class CPTShadow; + +/** + * @brief Enumeration of labeling policies + **/ +typedef enum _CPTAxisLabelingPolicy { + CPTAxisLabelingPolicyNone, ///< No labels provided; user sets labels and tick locations. + CPTAxisLabelingPolicyLocationsProvided, ///< User sets tick locations; axis makes labels. + CPTAxisLabelingPolicyFixedInterval, ///< Fixed interval labeling policy. + CPTAxisLabelingPolicyAutomatic, ///< Automatic labeling policy. + CPTAxisLabelingPolicyEqualDivisions ///< Divide the plot range into equal parts. +} +CPTAxisLabelingPolicy; + +#pragma mark - + +/** + * @brief Axis labeling delegate. + **/ +@protocol CPTAxisDelegate + +@optional + +/// @name Labels +/// @{ + +/** @brief (Optional) Determines if the axis should relabel itself now. + * @param axis The axis. + * @return YES if the axis should relabel now. + **/ +-(BOOL)axisShouldRelabel:(CPTAxis *)axis; + +/** @brief (Optional) The method is called after the axis is relabeled to allow the delegate to perform any + * necessary cleanup or further labeling actions. + * @param axis The axis. + **/ +-(void)axisDidRelabel:(CPTAxis *)axis; + +/** @brief (Optional) This method gives the delegate a chance to create custom labels for each tick. + * It can be used with any labeling policy. Returning NO will cause the axis not + * to update the labels. It is then the delegates responsiblity to do this. + * @param axis The axis. + * @param locations The locations of the major ticks. + * @return YES if the axis class should proceed with automatic labeling. + **/ +-(BOOL)axis:(CPTAxis *)axis shouldUpdateAxisLabelsAtLocations:(NSSet *)locations; + +/** @brief (Optional) This method gives the delegate a chance to create custom labels for each minor tick. + * It can be used with any labeling policy. Returning NO will cause the axis not + * to update the labels. It is then the delegates responsiblity to do this. + * @param axis The axis. + * @param locations The locations of the minor ticks. + * @return YES if the axis class should proceed with automatic labeling. + **/ +-(BOOL)axis:(CPTAxis *)axis shouldUpdateMinorAxisLabelsAtLocations:(NSSet *)locations; + +/// @} + +@end + +#pragma mark - + +@interface CPTAxis : CPTLayer { + @private + CPTCoordinate coordinate; + CPTPlotSpace *plotSpace; + NSSet *majorTickLocations; + NSSet *minorTickLocations; + CGFloat majorTickLength; + CGFloat minorTickLength; + CGFloat labelOffset; + CGFloat minorTickLabelOffset; + CGFloat labelRotation; + CGFloat minorTickLabelRotation; + CPTAlignment labelAlignment; + CPTAlignment minorTickLabelAlignment; + CPTLineStyle *axisLineStyle; + CPTLineStyle *majorTickLineStyle; + CPTLineStyle *minorTickLineStyle; + CPTLineStyle *majorGridLineStyle; + CPTLineStyle *minorGridLineStyle; + CPTLineCap *axisLineCapMin; + CPTLineCap *axisLineCapMax; + NSDecimal labelingOrigin; + NSDecimal majorIntervalLength; + NSUInteger minorTicksPerInterval; + NSUInteger preferredNumberOfMajorTicks; + CPTAxisLabelingPolicy labelingPolicy; + CPTTextStyle *labelTextStyle; + CPTTextStyle *minorTickLabelTextStyle; + CPTTextStyle *titleTextStyle; + NSNumberFormatter *labelFormatter; + NSNumberFormatter *minorTickLabelFormatter; + BOOL labelFormatterChanged; + BOOL minorLabelFormatterChanged; + NSSet *axisLabels; + NSSet *minorTickAxisLabels; + CPTAxisTitle *axisTitle; + NSString *title; + CGFloat titleOffset; + CGFloat titleRotation; + NSDecimal titleLocation; + CPTSign tickDirection; + BOOL needsRelabel; + NSArray *labelExclusionRanges; + CPTPlotRange *visibleRange; + CPTPlotRange *gridLinesRange; + NSArray *alternatingBandFills; + NSMutableArray *mutableBackgroundLimitBands; + BOOL separateLayers; + CPTShadow *labelShadow; + __cpt_weak CPTPlotArea *plotArea; + __cpt_weak CPTGridLines *minorGridLines; + __cpt_weak CPTGridLines *majorGridLines; +} + +/// @name Axis +/// @{ +@property (nonatomic, readwrite, copy) CPTLineStyle *axisLineStyle; +@property (nonatomic, readwrite, assign) CPTCoordinate coordinate; +@property (nonatomic, readwrite, assign) NSDecimal labelingOrigin; +@property (nonatomic, readwrite, assign) CPTSign tickDirection; +@property (nonatomic, readwrite, copy) CPTPlotRange *visibleRange; +@property (nonatomic, readwrite, copy) CPTLineCap *axisLineCapMin; +@property (nonatomic, readwrite, copy) CPTLineCap *axisLineCapMax; +/// @} + +/// @name Title +/// @{ +@property (nonatomic, readwrite, copy) CPTTextStyle *titleTextStyle; +@property (nonatomic, readwrite, retain) CPTAxisTitle *axisTitle; +@property (nonatomic, readwrite, assign) CGFloat titleOffset; +@property (nonatomic, readwrite, copy) NSString *title; +@property (nonatomic, readwrite, assign) CGFloat titleRotation; +@property (nonatomic, readwrite, assign) NSDecimal titleLocation; +@property (nonatomic, readonly, assign) NSDecimal defaultTitleLocation; +/// @} + +/// @name Labels +/// @{ +@property (nonatomic, readwrite, assign) CPTAxisLabelingPolicy labelingPolicy; +@property (nonatomic, readwrite, assign) CGFloat labelOffset; +@property (nonatomic, readwrite, assign) CGFloat minorTickLabelOffset; +@property (nonatomic, readwrite, assign) CGFloat labelRotation; +@property (nonatomic, readwrite, assign) CGFloat minorTickLabelRotation; +@property (nonatomic, readwrite, assign) CPTAlignment labelAlignment; +@property (nonatomic, readwrite, assign) CPTAlignment minorTickLabelAlignment; +@property (nonatomic, readwrite, copy) CPTTextStyle *labelTextStyle; +@property (nonatomic, readwrite, copy) CPTTextStyle *minorTickLabelTextStyle; +@property (nonatomic, readwrite, retain) NSNumberFormatter *labelFormatter; +@property (nonatomic, readwrite, retain) NSNumberFormatter *minorTickLabelFormatter; +@property (nonatomic, readwrite, retain) NSSet *axisLabels; +@property (nonatomic, readwrite, retain) NSSet *minorTickAxisLabels; +@property (nonatomic, readonly, assign) BOOL needsRelabel; +@property (nonatomic, readwrite, retain) NSArray *labelExclusionRanges; +@property (nonatomic, readwrite, retain) CPTShadow *labelShadow; +/// @} + +/// @name Major Ticks +/// @{ +@property (nonatomic, readwrite, assign) NSDecimal majorIntervalLength; +@property (nonatomic, readwrite, assign) CGFloat majorTickLength; +@property (nonatomic, readwrite, copy) CPTLineStyle *majorTickLineStyle; +@property (nonatomic, readwrite, retain) NSSet *majorTickLocations; +@property (nonatomic, readwrite, assign) NSUInteger preferredNumberOfMajorTicks; +/// @} + +/// @name Minor Ticks +/// @{ +@property (nonatomic, readwrite, assign) NSUInteger minorTicksPerInterval; +@property (nonatomic, readwrite, assign) CGFloat minorTickLength; +@property (nonatomic, readwrite, copy) CPTLineStyle *minorTickLineStyle; +@property (nonatomic, readwrite, retain) NSSet *minorTickLocations; +/// @} + +/// @name Grid Lines +/// @{ +@property (nonatomic, readwrite, copy) CPTLineStyle *majorGridLineStyle; +@property (nonatomic, readwrite, copy) CPTLineStyle *minorGridLineStyle; +@property (nonatomic, readwrite, copy) CPTPlotRange *gridLinesRange; +/// @} + +/// @name Background Bands +/// @{ +@property (nonatomic, readwrite, copy) NSArray *alternatingBandFills; +@property (nonatomic, readonly, retain) NSArray *backgroundLimitBands; +/// @} + +/// @name Plot Space +/// @{ +@property (nonatomic, readwrite, retain) CPTPlotSpace *plotSpace; +/// @} + +/// @name Layers +/// @{ +@property (nonatomic, readwrite, assign) BOOL separateLayers; +@property (nonatomic, readwrite, cpt_weak_property) __cpt_weak CPTPlotArea *plotArea; +@property (nonatomic, readonly, cpt_weak_property) __cpt_weak CPTGridLines *minorGridLines; +@property (nonatomic, readonly, cpt_weak_property) __cpt_weak CPTGridLines *majorGridLines; +@property (nonatomic, readonly, retain) CPTAxisSet *axisSet; +/// @} + +/// @name Labels +/// @{ +-(void)relabel; +-(void)setNeedsRelabel; +-(void)updateMajorTickLabels; +-(void)updateMinorTickLabels; +/// @} + +/// @name Ticks +/// @{ +-(NSSet *)filteredMajorTickLocations:(NSSet *)allLocations; +-(NSSet *)filteredMinorTickLocations:(NSSet *)allLocations; +/// @} + +/// @name Background Bands +/// @{ +-(void)addBackgroundLimitBand:(CPTLimitBand *)limitBand; +-(void)removeBackgroundLimitBand:(CPTLimitBand *)limitBand; +/// @} + +@end + +#pragma mark - + +/** @category CPTAxis(AbstractMethods) + * @brief CPTAxis abstract methods—must be overridden by subclasses + **/ +@interface CPTAxis(AbstractMethods) + +/// @name Coordinate Space Conversions +/// @{ +-(CGPoint)viewPointForCoordinateDecimalNumber:(NSDecimal)coordinateDecimalNumber; +/// @} + +/// @name Grid Lines +/// @{ +-(void)drawGridLinesInContext:(CGContextRef)context isMajor:(BOOL)major; +/// @} + +/// @name Background Bands +/// @{ +-(void)drawBackgroundBandsInContext:(CGContextRef)context; +-(void)drawBackgroundLimitsInContext:(CGContextRef)context; +/// @} + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTAxisLabel.h b/CorePlot.framework/Versions/A/Headers/CPTAxisLabel.h new file mode 100644 index 0000000..9c52b0c --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTAxisLabel.h @@ -0,0 +1,34 @@ +#import "CPTDefinitions.h" +#import + +@class CPTLayer; +@class CPTTextStyle; + +@interface CPTAxisLabel : NSObject { + @private + CPTLayer *contentLayer; + CGFloat offset; + CGFloat rotation; + CPTAlignment alignment; + NSDecimal tickLocation; +} + +@property (nonatomic, readwrite, retain) CPTLayer *contentLayer; +@property (nonatomic, readwrite, assign) CGFloat offset; +@property (nonatomic, readwrite, assign) CGFloat rotation; +@property (nonatomic, readwrite, assign) CPTAlignment alignment; +@property (nonatomic, readwrite) NSDecimal tickLocation; + +/// @name Initialization +/// @{ +-(id)initWithText:(NSString *)newText textStyle:(CPTTextStyle *)style; +-(id)initWithContentLayer:(CPTLayer *)layer; +/// @} + +/// @name Layout +/// @{ +-(void)positionRelativeToViewPoint:(CGPoint)point forCoordinate:(CPTCoordinate)coordinate inDirection:(CPTSign)direction; +-(void)positionBetweenViewPoint:(CGPoint)firstPoint andViewPoint:(CGPoint)secondPoint forCoordinate:(CPTCoordinate)coordinate inDirection:(CPTSign)direction; +/// @} + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTAxisSet.h b/CorePlot.framework/Versions/A/Headers/CPTAxisSet.h new file mode 100644 index 0000000..57d590b --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTAxisSet.h @@ -0,0 +1,20 @@ +#import "CPTLayer.h" +#import + +@class CPTLineStyle; + +@interface CPTAxisSet : CPTLayer { + @private + NSArray *axes; + CPTLineStyle *borderLineStyle; +} + +@property (nonatomic, readwrite, retain) NSArray *axes; +@property (nonatomic, readwrite, copy) CPTLineStyle *borderLineStyle; + +/// @name Labels +/// @{ +-(void)relabelAxes; +/// @} + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTAxisTitle.h b/CorePlot.framework/Versions/A/Headers/CPTAxisTitle.h new file mode 100644 index 0000000..81370b6 --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTAxisTitle.h @@ -0,0 +1,7 @@ +#import "CPTAxisLabel.h" +#import + +@interface CPTAxisTitle : CPTAxisLabel { +} + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTBarPlot.h b/CorePlot.framework/Versions/A/Headers/CPTBarPlot.h new file mode 100644 index 0000000..b5bca37 --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTBarPlot.h @@ -0,0 +1,134 @@ +#import "CPTDefinitions.h" +#import "CPTPlot.h" +#import + +/// @file + +@class CPTLineStyle; +@class CPTMutableNumericData; +@class CPTNumericData; +@class CPTFill; +@class CPTPlotRange; +@class CPTColor; +@class CPTBarPlot; +@class CPTTextLayer; +@class CPTTextStyle; + +/// @ingroup plotBindingsBarPlot +/// @{ +extern NSString *const CPTBarPlotBindingBarLocations; +extern NSString *const CPTBarPlotBindingBarTips; +extern NSString *const CPTBarPlotBindingBarBases; +/// @} + +/** + * @brief Enumeration of bar plot data source field types + **/ +typedef enum _CPTBarPlotField { + CPTBarPlotFieldBarLocation, ///< Bar location on independent coordinate axis. + CPTBarPlotFieldBarTip, ///< Bar tip value. + CPTBarPlotFieldBarBase ///< Bar base (used only if @link CPTBarPlot::barBasesVary barBasesVary @endlink is YES). +} +CPTBarPlotField; + +#pragma mark - + +/** + * @brief A bar plot data source. + **/ +@protocol CPTBarPlotDataSource +@optional + +/// @name Bar Style +/// @{ + +/** @brief (Optional) Gets a bar fill for the given bar plot. + * @param barPlot The bar plot. + * @param index The data index of interest. + * @return The bar fill for the bar with the given index. If the data source returns nil, the default fill is used. + * If the data source returns an NSNull object, no fill is drawn. + **/ +-(CPTFill *)barFillForBarPlot:(CPTBarPlot *)barPlot recordIndex:(NSUInteger)index; + +/** @brief (Optional) Gets a bar line style for the given bar plot. + * @param barPlot The bar plot. + * @param index The data index of interest. + * @return The bar line style for the bar with the given index. If the data source returns nil, the default line style is used. + * If the data source returns an NSNull object, no line is drawn. + **/ +-(CPTLineStyle *)barLineStyleForBarPlot:(CPTBarPlot *)barPlot recordIndex:(NSUInteger)index; + +/// @} + +/// @name Legends +/// @{ + +/** @brief (Optional) Gets the legend title for the given bar plot bar. + * @param barPlot The bar plot. + * @param index The data index of interest. + * @return The title text for the legend entry for the point with the given index. + **/ +-(NSString *)legendTitleForBarPlot:(CPTBarPlot *)barPlot recordIndex:(NSUInteger)index; + +/// @} +@end + +#pragma mark - + +/** + * @brief Bar plot delegate. + **/ +@protocol CPTBarPlotDelegate + +@optional + +/// @name Point Selection +/// @{ + +/** @brief (Optional) Informs delegate that a point was touched. + * @param plot The scatter plot. + * @param index Index of touched point + **/ +-(void)barPlot:(CPTBarPlot *)plot barWasSelectedAtRecordIndex:(NSUInteger)index; + +/// @} + +@end + +#pragma mark - + +@interface CPTBarPlot : CPTPlot { + @private + CPTLineStyle *lineStyle; + CPTFill *fill; + NSDecimal barWidth; + CGFloat barWidthScale; + NSDecimal barOffset; + CGFloat barOffsetScale; + CGFloat barCornerRadius; + NSDecimal baseValue; + BOOL barsAreHorizontal; + BOOL barBasesVary; + BOOL barWidthsAreInViewCoordinates; + CPTPlotRange *plotRange; +} + +@property (nonatomic, readwrite, assign) BOOL barWidthsAreInViewCoordinates; +@property (nonatomic, readwrite, assign) NSDecimal barWidth; +@property (nonatomic, readwrite, assign) CGFloat barWidthScale; +@property (nonatomic, readwrite, assign) NSDecimal barOffset; +@property (nonatomic, readwrite, assign) CGFloat barOffsetScale; +@property (nonatomic, readwrite, assign) CGFloat barCornerRadius; +@property (nonatomic, readwrite, copy) CPTLineStyle *lineStyle; +@property (nonatomic, readwrite, copy) CPTFill *fill; +@property (nonatomic, readwrite, assign) BOOL barsAreHorizontal; +@property (nonatomic, readwrite, assign) NSDecimal baseValue; +@property (nonatomic, readwrite, assign) BOOL barBasesVary; +@property (nonatomic, readwrite, copy) CPTPlotRange *plotRange; + +/// @name Factory Methods +/// @{ ++(CPTBarPlot *)tubularBarPlotWithColor:(CPTColor *)color horizontalBars:(BOOL)horizontal; +/// @} + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTBorderedLayer.h b/CorePlot.framework/Versions/A/Headers/CPTBorderedLayer.h new file mode 100644 index 0000000..8b0ad67 --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTBorderedLayer.h @@ -0,0 +1,16 @@ +#import "CPTAnnotationHostLayer.h" +#import + +@class CPTLineStyle; +@class CPTFill; + +@interface CPTBorderedLayer : CPTAnnotationHostLayer { + @private + CPTLineStyle *borderLineStyle; + CPTFill *fill; +} + +@property (nonatomic, readwrite, copy) CPTLineStyle *borderLineStyle; +@property (nonatomic, readwrite, copy) CPTFill *fill; + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTColor.h b/CorePlot.framework/Versions/A/Headers/CPTColor.h new file mode 100644 index 0000000..db93fb7 --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTColor.h @@ -0,0 +1,42 @@ +#import +#import + +@interface CPTColor : NSObject { + @private + CGColorRef cgColor; +} + +@property (nonatomic, readonly, assign) CGColorRef cgColor; + +/// @name Factory Methods +/// @{ ++(CPTColor *)clearColor; ++(CPTColor *)whiteColor; ++(CPTColor *)lightGrayColor; ++(CPTColor *)grayColor; ++(CPTColor *)darkGrayColor; ++(CPTColor *)blackColor; ++(CPTColor *)redColor; ++(CPTColor *)greenColor; ++(CPTColor *)blueColor; ++(CPTColor *)cyanColor; ++(CPTColor *)yellowColor; ++(CPTColor *)magentaColor; ++(CPTColor *)orangeColor; ++(CPTColor *)purpleColor; ++(CPTColor *)brownColor; + ++(CPTColor *)colorWithCGColor:(CGColorRef)newCGColor; ++(CPTColor *)colorWithComponentRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha; ++(CPTColor *)colorWithGenericGray:(CGFloat)gray; +/// @} + +/// @name Initialization +/// @{ +-(id)initWithCGColor:(CGColorRef)cgColor; +-(id)initWithComponentRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha; + +-(CPTColor *)colorWithAlphaComponent:(CGFloat)alpha; +/// @} + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTColorSpace.h b/CorePlot.framework/Versions/A/Headers/CPTColorSpace.h new file mode 100644 index 0000000..ac89b30 --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTColorSpace.h @@ -0,0 +1,21 @@ +#import +#import + +@interface CPTColorSpace : NSObject { + @private + CGColorSpaceRef cgColorSpace; +} + +@property (nonatomic, readonly, assign) CGColorSpaceRef cgColorSpace; + +/// @name Factory Methods +/// @{ ++(CPTColorSpace *)genericRGBSpace; +/// @} + +/// @name Initialization +/// @{ +-(id)initWithCGColorSpace:(CGColorSpaceRef)colorSpace; +/// @} + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTConstraints.h b/CorePlot.framework/Versions/A/Headers/CPTConstraints.h new file mode 100644 index 0000000..e6885d7 --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTConstraints.h @@ -0,0 +1,38 @@ +#import +#import + +@interface CPTConstraints : NSObject { +} + +/// @name Factory Methods +/// @{ ++(CPTConstraints *)constraintWithLowerOffset:(CGFloat)newOffset; ++(CPTConstraints *)constraintWithUpperOffset:(CGFloat)newOffset; ++(CPTConstraints *)constraintWithRelativeOffset:(CGFloat)newOffset; +/// @} + +/// @name Initialization +/// @{ +-(id)initWithLowerOffset:(CGFloat)newOffset; +-(id)initWithUpperOffset:(CGFloat)newOffset; +-(id)initWithRelativeOffset:(CGFloat)newOffset; +/// @} + +@end + +/** @category CPTConstraints(AbstractMethods) + * @brief CPTConstraints abstract methods—must be overridden by subclasses + **/ +@interface CPTConstraints(AbstractMethods) + +/// @name Comparison +/// @{ +-(BOOL)isEqualToConstraint:(CPTConstraints *)otherConstraint; +/// @} + +/// @name Position +/// @{ +-(CGFloat)positionForLowerBound:(CGFloat)lowerBound upperBound:(CGFloat)upperBound; +/// @} + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTDecimalNumberValueTransformer.h b/CorePlot.framework/Versions/A/Headers/CPTDecimalNumberValueTransformer.h new file mode 100644 index 0000000..8d69f95 --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTDecimalNumberValueTransformer.h @@ -0,0 +1,6 @@ +#import + +@interface CPTDecimalNumberValueTransformer : NSValueTransformer { +} + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTDefinitions.h b/CorePlot.framework/Versions/A/Headers/CPTDefinitions.h new file mode 100644 index 0000000..3881d50 --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTDefinitions.h @@ -0,0 +1,136 @@ +#import +#import + +#import +#import + +/// @file + +/** + * @def CPT_SDK_SUPPORTS_WEAK + * @brief Defined as 1 if the compiler and active SDK support weak references, 0 otherwise. + **/ + +/** + * @def __cpt_weak + * @brief A custom definition for ARC weak references that falls back to unsafe unretained values on older platforms. + **/ + +/** + * @def cpt_weak_property + * @brief A custom definition for ARC weak properties that falls back to assign on older platforms. + **/ + +// This is based on Ryan Petrich's ZWRCompatibility: https://github.com/rpetrich/ZWRCompatibility + +#if TARGET_OS_IPHONE && defined(__IPHONE_5_0) && (__IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_5_0) && __clang__ && (__clang_major__ >= 3) +#define CPT_SDK_SUPPORTS_WEAK 1 +#elif TARGET_OS_MAC && defined(__MAC_10_7) && (MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_7) && __clang__ && (__clang_major__ >= 3) +#define CPT_SDK_SUPPORTS_WEAK 1 +#else +#define CPT_SDK_SUPPORTS_WEAK 0 +#endif + +#if CPT_SDK_SUPPORTS_WEAK +#define __cpt_weak __weak +#define cpt_weak_property weak +#else +#if __clang__ && (__clang_major__ >= 3) +#define __cpt_weak __unsafe_unretained +#else +#define __cpt_weak +#endif +#define cpt_weak_property assign +#endif + +/** + * @brief Enumeration of numeric types + **/ +typedef enum _CPTNumericType { + CPTNumericTypeInteger, ///< Integer + CPTNumericTypeFloat, ///< Float + CPTNumericTypeDouble ///< Double +} +CPTNumericType; + +/** + * @brief Enumeration of error bar types + **/ +typedef enum _CPTErrorBarType { + CPTErrorBarTypeCustom, ///< Custom error bars + CPTErrorBarTypeConstantRatio, ///< Constant ratio error bars + CPTErrorBarTypeConstantValue ///< Constant value error bars +} +CPTErrorBarType; + +/** + * @brief Enumeration of axis scale types + **/ +typedef enum _CPTScaleType { + CPTScaleTypeLinear, ///< Linear axis scale + CPTScaleTypeLog, ///< Logarithmic axis scale + CPTScaleTypeAngular, ///< Angular axis scale (not implemented) + CPTScaleTypeDateTime, ///< Date/time axis scale (not implemented) + CPTScaleTypeCategory ///< Category axis scale (not implemented) +} +CPTScaleType; + +/** + * @brief Enumeration of axis coordinates + **/ +typedef enum _CPTCoordinate { + CPTCoordinateX = 0, ///< X axis + CPTCoordinateY = 1, ///< Y axis + CPTCoordinateZ = 2 ///< Z axis +} +CPTCoordinate; + +/** + * @brief RGBA color for gradients + **/ +typedef struct _CPTRGBAColor { + CGFloat red; ///< The red component (0 ≤ red ≤ 1). + CGFloat green; ///< The green component (0 ≤ green ≤ 1). + CGFloat blue; ///< The blue component (0 ≤ blue ≤ 1). + CGFloat alpha; ///< The alpha component (0 ≤ alpha ≤ 1). +} +CPTRGBAColor; + +/** + * @brief Enumeration of label positioning offset directions + **/ +typedef enum _CPTSign { + CPTSignNone = 0, ///< No offset + CPTSignPositive = +1, ///< Positive offset + CPTSignNegative = -1 ///< Negative offset +} +CPTSign; + +/** + * @brief Locations around the edge of a rectangle. + **/ +typedef enum _CPTRectAnchor { + CPTRectAnchorBottomLeft, ///< The bottom left corner + CPTRectAnchorBottom, ///< The bottom center + CPTRectAnchorBottomRight, ///< The bottom right corner + CPTRectAnchorLeft, ///< The left middle + CPTRectAnchorRight, ///< The right middle + CPTRectAnchorTopLeft, ///< The top left corner + CPTRectAnchorTop, ///< The top center + CPTRectAnchorTopRight, ///< The top right + CPTRectAnchorCenter ///< The center of the rect +} +CPTRectAnchor; + +/** + * @brief Label and constraint alignment constants. + **/ +typedef enum _CPTAlignment { + CPTAlignmentLeft, ///< Align horizontally to the left side. + CPTAlignmentCenter, ///< Align horizontally to the center. + CPTAlignmentRight, ///< Align horizontally to the right side. + CPTAlignmentTop, ///< Align vertically to the top. + CPTAlignmentMiddle, ///< Align vertically to the middle. + CPTAlignmentBottom ///< Align vertically to the bottom. +} +CPTAlignment; diff --git a/CorePlot.framework/Versions/A/Headers/CPTExceptions.h b/CorePlot.framework/Versions/A/Headers/CPTExceptions.h new file mode 100644 index 0000000..7d262d4 --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTExceptions.h @@ -0,0 +1,10 @@ +#import + +/// @file + +/// @name Custom Exception Identifiers +/// @{ +extern NSString *const CPTException; +extern NSString *const CPTDataException; +extern NSString *const CPTNumericDataException; +/// @} diff --git a/CorePlot.framework/Versions/A/Headers/CPTFill.h b/CorePlot.framework/Versions/A/Headers/CPTFill.h new file mode 100644 index 0000000..01ddbe7 --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTFill.h @@ -0,0 +1,38 @@ +#import +#import + +@class CPTGradient; +@class CPTImage; +@class CPTColor; + +@interface CPTFill : NSObject { +} + +/// @name Factory Methods +/// @{ ++(CPTFill *)fillWithColor:(CPTColor *)aColor; ++(CPTFill *)fillWithGradient:(CPTGradient *)aGradient; ++(CPTFill *)fillWithImage:(CPTImage *)anImage; +/// @} + +/// @name Initialization +/// @{ +-(id)initWithColor:(CPTColor *)aColor; +-(id)initWithGradient:(CPTGradient *)aGradient; +-(id)initWithImage:(CPTImage *)anImage; +/// @} + +@end + +/** @category CPTFill(AbstractMethods) + * @brief CPTFill abstract methods—must be overridden by subclasses + **/ +@interface CPTFill(AbstractMethods) + +/// @name Drawing +/// @{ +-(void)fillRect:(CGRect)theRect inContext:(CGContextRef)theContext; +-(void)fillPathInContext:(CGContextRef)theContext; +/// @} + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTGradient.h b/CorePlot.framework/Versions/A/Headers/CPTGradient.h new file mode 100644 index 0000000..981575d --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTGradient.h @@ -0,0 +1,100 @@ +// Based on CTGradient (http://blog.oofn.net/2006/01/15/gradients-in-cocoa/) +// CTGradient is in public domain (Thanks Chad Weider!) + +/// @file + +#import "CPTDefinitions.h" +#import + +/** + * @brief A structure representing one node in a linked list of RGBA colors. + **/ +typedef struct _CPTGradientElement { + CPTRGBAColor color; ///< Color + CGFloat position; ///< Gradient position (0 ≤ position ≤ 1) + + struct _CPTGradientElement *nextElement; ///< Pointer to the next CPTGradientElement in the list (last element == NULL) +} +CPTGradientElement; + +/** + * @brief Enumeration of blending modes + **/ +typedef enum _CPTBlendingMode { + CPTLinearBlendingMode, ///< Linear blending mode + CPTChromaticBlendingMode, ///< Chromatic blending mode + CPTInverseChromaticBlendingMode ///< Inverse chromatic blending mode +} +CPTGradientBlendingMode; + +/** + * @brief Enumeration of gradient types + **/ +typedef enum _CPTGradientType { + CPTGradientTypeAxial, ///< Axial gradient + CPTGradientTypeRadial ///< Radial gradient +} +CPTGradientType; + +@class CPTColorSpace; +@class CPTColor; + +@interface CPTGradient : NSObject { + @private + CPTColorSpace *colorspace; + CPTGradientElement *elementList; + CPTGradientBlendingMode blendingMode; + CGFunctionRef gradientFunction; + CGFloat angle; // angle in degrees + CPTGradientType gradientType; +} + +@property (nonatomic, readonly, assign) CPTGradientBlendingMode blendingMode; +@property (nonatomic, readwrite, assign) CGFloat angle; +@property (nonatomic, readwrite, assign) CPTGradientType gradientType; + +/// @name Factory Methods +/// @{ ++(CPTGradient *)gradientWithBeginningColor:(CPTColor *)begin endingColor:(CPTColor *)end; ++(CPTGradient *)gradientWithBeginningColor:(CPTColor *)begin endingColor:(CPTColor *)end beginningPosition:(CGFloat)beginningPosition endingPosition:(CGFloat)endingPosition; + ++(CPTGradient *)aquaSelectedGradient; ++(CPTGradient *)aquaNormalGradient; ++(CPTGradient *)aquaPressedGradient; + ++(CPTGradient *)unifiedSelectedGradient; ++(CPTGradient *)unifiedNormalGradient; ++(CPTGradient *)unifiedPressedGradient; ++(CPTGradient *)unifiedDarkGradient; + ++(CPTGradient *)sourceListSelectedGradient; ++(CPTGradient *)sourceListUnselectedGradient; + ++(CPTGradient *)rainbowGradient; ++(CPTGradient *)hydrogenSpectrumGradient; +/// @} + +/// @name Modification +/// @{ +-(CPTGradient *)gradientWithAlphaComponent:(CGFloat)alpha; +-(CPTGradient *)gradientWithBlendingMode:(CPTGradientBlendingMode)mode; + +-(CPTGradient *)addColorStop:(CPTColor *)color atPosition:(CGFloat)position; // positions given relative to [0,1] +-(CPTGradient *)removeColorStopAtIndex:(NSUInteger)index; +-(CPTGradient *)removeColorStopAtPosition:(CGFloat)position; +/// @} + +/// @name Information +/// @{ +-(CGColorRef)newColorStopAtIndex:(NSUInteger)index; +-(CGColorRef)newColorAtPosition:(CGFloat)position; +/// @} + +/// @name Drawing +/// @{ +-(void)drawSwatchInRect:(CGRect)rect inContext:(CGContextRef)context; +-(void)fillRect:(CGRect)rect inContext:(CGContextRef)context; +-(void)fillPathInContext:(CGContextRef)context; +/// @} + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTGraph.h b/CorePlot.framework/Versions/A/Headers/CPTGraph.h new file mode 100644 index 0000000..6d1a183 --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTGraph.h @@ -0,0 +1,136 @@ +// Abstract class +#import "CPTBorderedLayer.h" +#import "CPTDefinitions.h" + +/// @file + +@class CPTAxisSet; +@class CPTLegend; +@class CPTPlot; +@class CPTPlotAreaFrame; +@class CPTPlotSpace; +@class CPTTheme; +@class CPTTextStyle; +@class CPTLayerAnnotation; + +/// @name Graph +/// @{ + +/** @brief Notification sent by various objects to tell the graph it should redraw itself. + * @ingroup notification + **/ +extern NSString *const CPTGraphNeedsRedrawNotification; + +/// @} + +/** + * @brief Enumeration of graph layers. + **/ +typedef enum _CPTGraphLayerType { + CPTGraphLayerTypeMinorGridLines, ///< Minor grid lines. + CPTGraphLayerTypeMajorGridLines, ///< Major grid lines. + CPTGraphLayerTypeAxisLines, ///< Axis lines. + CPTGraphLayerTypePlots, ///< Plots. + CPTGraphLayerTypeAxisLabels, ///< Axis labels. + CPTGraphLayerTypeAxisTitles ///< Axis titles. +} +CPTGraphLayerType; + +#pragma mark - + +@interface CPTGraph : CPTBorderedLayer { + @private + CPTPlotAreaFrame *plotAreaFrame; + NSMutableArray *plots; + NSMutableArray *plotSpaces; + NSString *title; + CPTTextStyle *titleTextStyle; + CPTRectAnchor titlePlotAreaFrameAnchor; + CGPoint titleDisplacement; + CPTLayerAnnotation *titleAnnotation; + CPTLegend *legend; + CPTLayerAnnotation *legendAnnotation; + CPTRectAnchor legendAnchor; + CGPoint legendDisplacement; +} + +/// @name Title +/// @{ +@property (nonatomic, readwrite, copy) NSString *title; +@property (nonatomic, readwrite, copy) CPTTextStyle *titleTextStyle; +@property (nonatomic, readwrite, assign) CGPoint titleDisplacement; +@property (nonatomic, readwrite, assign) CPTRectAnchor titlePlotAreaFrameAnchor; +/// @} + +/// @name Layers +/// @{ +@property (nonatomic, readwrite, retain) CPTAxisSet *axisSet; +@property (nonatomic, readwrite, retain) CPTPlotAreaFrame *plotAreaFrame; +@property (nonatomic, readonly, retain) CPTPlotSpace *defaultPlotSpace; +@property (nonatomic, readwrite, retain) NSArray *topDownLayerOrder; +/// @} + +/// @name Legend +/// @{ +@property (nonatomic, readwrite, retain) CPTLegend *legend; +@property (nonatomic, readwrite, assign) CPTRectAnchor legendAnchor; +@property (nonatomic, readwrite, assign) CGPoint legendDisplacement; +/// @} + +/// @name Data Source +/// @{ +-(void)reloadData; +-(void)reloadDataIfNeeded; +/// @} + +/// @name Retrieving Plots +/// @{ +-(NSArray *)allPlots; +-(CPTPlot *)plotAtIndex:(NSUInteger)index; +-(CPTPlot *)plotWithIdentifier:(id)identifier; +/// @} + +/// @name Adding and Removing Plots +/// @{ +-(void)addPlot:(CPTPlot *)plot; +-(void)addPlot:(CPTPlot *)plot toPlotSpace:(CPTPlotSpace *)space; +-(void)removePlot:(CPTPlot *)plot; +-(void)removePlotWithIdentifier:(id)identifier; +-(void)insertPlot:(CPTPlot *)plot atIndex:(NSUInteger)index; +-(void)insertPlot:(CPTPlot *)plot atIndex:(NSUInteger)index intoPlotSpace:(CPTPlotSpace *)space; +/// @} + +/// @name Retrieving Plot Spaces +/// @{ +-(NSArray *)allPlotSpaces; +-(CPTPlotSpace *)plotSpaceAtIndex:(NSUInteger)index; +-(CPTPlotSpace *)plotSpaceWithIdentifier:(id)identifier; +/// @} + +/// @name Adding and Removing Plot Spaces +/// @{ +-(void)addPlotSpace:(CPTPlotSpace *)space; +-(void)removePlotSpace:(CPTPlotSpace *)plotSpace; +/// @} + +/// @name Themes +/// @{ +-(void)applyTheme:(CPTTheme *)theme; +/// @} + +@end + +#pragma mark - + +/** @category CPTGraph(AbstractFactoryMethods) + * @brief CPTGraph abstract methods—must be overridden by subclasses + **/ +@interface CPTGraph(AbstractFactoryMethods) + +/// @name Factory Methods +/// @{ +-(CPTPlotSpace *)newPlotSpace; +-(CPTAxisSet *)newAxisSet; +/// @} + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTGraphHostingView.h b/CorePlot.framework/Versions/A/Headers/CPTGraphHostingView.h new file mode 100644 index 0000000..869fa4b --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTGraphHostingView.h @@ -0,0 +1,12 @@ +#import + +@class CPTGraph; + +@interface CPTGraphHostingView : NSView { + @private + CPTGraph *hostedGraph; +} + +@property (nonatomic, readwrite, retain) CPTGraph *hostedGraph; + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTImage.h b/CorePlot.framework/Versions/A/Headers/CPTImage.h new file mode 100644 index 0000000..506d6a6 --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTImage.h @@ -0,0 +1,36 @@ +#import +#import + +@interface CPTImage : NSObject { + @private + CGImageRef image; + CGFloat scale; + BOOL tiled; + BOOL tileAnchoredToContext; +} + +@property (nonatomic, readwrite, assign) CGImageRef image; +@property (nonatomic, readwrite, assign) CGFloat scale; +@property (nonatomic, readwrite, assign, getter = isTiled) BOOL tiled; +@property (nonatomic, readwrite, assign) BOOL tileAnchoredToContext; + +/// @name Factory Methods +/// @{ ++(CPTImage *)imageWithCGImage:(CGImageRef)anImage scale:(CGFloat)newScale; ++(CPTImage *)imageWithCGImage:(CGImageRef)anImage; ++(CPTImage *)imageForPNGFile:(NSString *)path; +/// @} + +/// @name Initialization +/// @{ +-(id)initWithCGImage:(CGImageRef)anImage scale:(CGFloat)newScale; +-(id)initWithCGImage:(CGImageRef)anImage; +-(id)initForPNGFile:(NSString *)path; +/// @} + +/// @name Drawing +/// @{ +-(void)drawInRect:(CGRect)rect inContext:(CGContextRef)context; +/// @} + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTLayer.h b/CorePlot.framework/Versions/A/Headers/CPTLayer.h new file mode 100644 index 0000000..3d0d04f --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTLayer.h @@ -0,0 +1,109 @@ +#import "CPTDefinitions.h" +#import "CPTResponder.h" +#import +#import + +@class CPTGraph; +@class CPTShadow; + +@interface CPTLayer : CALayer { + @private + CGFloat paddingLeft; + CGFloat paddingTop; + CGFloat paddingRight; + CGFloat paddingBottom; + BOOL masksToBorder; + CPTShadow *shadow; + BOOL renderingRecursively; + BOOL useFastRendering; + __cpt_weak CPTGraph *graph; + CGPathRef outerBorderPath; + CGPathRef innerBorderPath; + id identifier; +} + +/// @name Graph +/// @{ +@property (nonatomic, readwrite, cpt_weak_property) __cpt_weak CPTGraph *graph; +/// @} + +/// @name Padding +/// @{ +@property (nonatomic, readwrite) CGFloat paddingLeft; +@property (nonatomic, readwrite) CGFloat paddingTop; +@property (nonatomic, readwrite) CGFloat paddingRight; +@property (nonatomic, readwrite) CGFloat paddingBottom; +/// @} + +/// @name Drawing +/// @{ +@property (readwrite, assign) CGFloat contentsScale; +@property (nonatomic, readonly, assign) BOOL useFastRendering; +@property (nonatomic, readwrite, copy) CPTShadow *shadow; +/// @} + +/// @name Masking +/// @{ +@property (nonatomic, readwrite, assign) BOOL masksToBorder; +@property (nonatomic, readwrite, assign) CGPathRef outerBorderPath; +@property (nonatomic, readwrite, assign) CGPathRef innerBorderPath; +@property (nonatomic, readonly, assign) CGPathRef maskingPath; +@property (nonatomic, readonly, assign) CGPathRef sublayerMaskingPath; +/// @} + +/// @name Identification +/// @{ +@property (nonatomic, readwrite, copy) id identifier; +/// @} + +/// @name Layout +/// @{ +@property (readonly) NSSet *sublayersExcludedFromAutomaticLayout; +/// @} + +/// @name Initialization +/// @{ +-(id)initWithFrame:(CGRect)newFrame; +/// @} + +/// @name Drawing +/// @{ +-(void)renderAsVectorInContext:(CGContextRef)context; +-(void)recursivelyRenderInContext:(CGContextRef)context; +-(void)layoutAndRenderInContext:(CGContextRef)context; +-(NSData *)dataForPDFRepresentationOfLayer; +/// @} + +/// @name Masking +/// @{ +-(void)applySublayerMaskToContext:(CGContextRef)context forSublayer:(CPTLayer *)sublayer withOffset:(CGPoint)offset; +-(void)applyMaskToContext:(CGContextRef)context; +/// @} + +/// @name Layout +/// @{ +-(void)pixelAlign; +-(void)sublayerMarginLeft:(CGFloat *)left top:(CGFloat *)top right:(CGFloat *)right bottom:(CGFloat *)bottom; +/// @} + +/// @name Information +/// @{ +-(void)logLayers; +/// @} + +@end + +/// @cond +// for MacOS 10.6 SDK compatibility +#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE +#else +#if MAC_OS_X_VERSION_MAX_ALLOWED < 1070 +@interface CALayer(CPTExtensions) + +@property (readwrite) CGFloat contentsScale; + +@end +#endif +#endif + +/// @endcond diff --git a/CorePlot.framework/Versions/A/Headers/CPTLayerAnnotation.h b/CorePlot.framework/Versions/A/Headers/CPTLayerAnnotation.h new file mode 100644 index 0000000..70d081e --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTLayerAnnotation.h @@ -0,0 +1,20 @@ +#import "CPTAnnotation.h" +#import "CPTDefinitions.h" +#import + +@class CPTConstraints; + +@interface CPTLayerAnnotation : CPTAnnotation { + @private + __cpt_weak CPTLayer *anchorLayer; + CPTConstraints *xConstraints; + CPTConstraints *yConstraints; + CPTRectAnchor rectAnchor; +} + +@property (nonatomic, readonly, cpt_weak_property) __cpt_weak CPTLayer *anchorLayer; +@property (nonatomic, readwrite, assign) CPTRectAnchor rectAnchor; + +-(id)initWithAnchorLayer:(CPTLayer *)anchorLayer; + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTLegend.h b/CorePlot.framework/Versions/A/Headers/CPTLegend.h new file mode 100644 index 0000000..fc73325 --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTLegend.h @@ -0,0 +1,135 @@ +#import "CPTBorderedLayer.h" +#import + +/// @file + +@class CPTLegend; +@class CPTPlot; +@class CPTTextStyle; + +/// @name Legend +/// @{ + +/** @brief Notification sent by plots to tell the legend it should redraw itself. + * @ingroup notification + **/ +extern NSString *const CPTLegendNeedsRedrawForPlotNotification; + +/** @brief Notification sent by plots to tell the legend it should update its layout and redraw itself. + * @ingroup notification + **/ +extern NSString *const CPTLegendNeedsLayoutForPlotNotification; + +/** @brief Notification sent by plots to tell the legend it should reload all legend entries. + * @ingroup notification + **/ +extern NSString *const CPTLegendNeedsReloadEntriesForPlotNotification; + +/// @} + +/** + * @brief Axis labeling delegate. + **/ +@protocol CPTLegendDelegate + +/// @name Drawing +/// @{ + +/** @brief (Required) This method gives the delegate a chance to draw custom swatches for each legend entry. + * + * The "swatch" is the graphical part of the legend entry, usually accompanied by a text title + * that will be drawn by the legend. Returning NO will cause the legend to not draw the default + * legend graphics. It is then the delegate's responsiblity to do this. + * @param legend The legend. + * @param index The zero-based index of the legend entry for the given plot. + * @param plot The plot. + * @param rect The bounding rectangle to use when drawing the swatch. + * @param context The graphics context to draw into. + * @return YES if the legend should draw the default swatch or NO if the delegate handled the drawing. + **/ +-(BOOL)legend:(CPTLegend *)legend shouldDrawSwatchAtIndex:(NSUInteger)index forPlot:(CPTPlot *)plot inRect:(CGRect)rect inContext:(CGContextRef)context; + +/// @} + +@end + +#pragma mark - + +@interface CPTLegend : CPTBorderedLayer { + @private + NSMutableArray *plots; + NSMutableArray *legendEntries; + BOOL layoutChanged; + CPTTextStyle *textStyle; + CGSize swatchSize; + CPTLineStyle *swatchBorderLineStyle; + CGFloat swatchCornerRadius; + CPTFill *swatchFill; + NSUInteger numberOfRows; + NSUInteger numberOfColumns; + BOOL equalRows; + BOOL equalColumns; + NSArray *rowHeights; + NSArray *rowHeightsThatFit; + NSArray *columnWidths; + NSArray *columnWidthsThatFit; + CGFloat columnMargin; + CGFloat rowMargin; + CGFloat titleOffset; +} + +/// @name Formatting +/// @{ +@property (nonatomic, readwrite, copy) CPTTextStyle *textStyle; +@property (nonatomic, readwrite, assign) CGSize swatchSize; +@property (nonatomic, readwrite, copy) CPTLineStyle *swatchBorderLineStyle; +@property (nonatomic, readwrite, assign) CGFloat swatchCornerRadius; +@property (nonatomic, readwrite, copy) CPTFill *swatchFill; +/// @} + +/// @name Layout +/// @{ +@property (nonatomic, readonly, assign) BOOL layoutChanged; +@property (nonatomic, readwrite, assign) NSUInteger numberOfRows; +@property (nonatomic, readwrite, assign) NSUInteger numberOfColumns; +@property (nonatomic, readwrite, assign) BOOL equalRows; +@property (nonatomic, readwrite, assign) BOOL equalColumns; +@property (nonatomic, readwrite, copy) NSArray *rowHeights; +@property (nonatomic, readonly, retain) NSArray *rowHeightsThatFit; +@property (nonatomic, readwrite, copy) NSArray *columnWidths; +@property (nonatomic, readonly, retain) NSArray *columnWidthsThatFit; +@property (nonatomic, readwrite, assign) CGFloat columnMargin; +@property (nonatomic, readwrite, assign) CGFloat rowMargin; +@property (nonatomic, readwrite, assign) CGFloat titleOffset; +/// @} + +/// @name Factory Methods +/// @{ ++(id)legendWithPlots:(NSArray *)newPlots; ++(id)legendWithGraph:(CPTGraph *)graph; +/// @} + +/// @name Initialization +/// @{ +-(id)initWithPlots:(NSArray *)newPlots; +-(id)initWithGraph:(CPTGraph *)graph; +/// @} + +/// @name Plots +/// @{ +-(NSArray *)allPlots; +-(CPTPlot *)plotAtIndex:(NSUInteger)index; +-(CPTPlot *)plotWithIdentifier:(id)identifier; + +-(void)addPlot:(CPTPlot *)plot; +-(void)insertPlot:(CPTPlot *)plot atIndex:(NSUInteger)index; +-(void)removePlot:(CPTPlot *)plot; +-(void)removePlotWithIdentifier:(id)identifier; +/// @} + +/// @name Layout +/// @{ +-(void)setLayoutChanged; +/// @} + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTLegendEntry.h b/CorePlot.framework/Versions/A/Headers/CPTLegendEntry.h new file mode 100644 index 0000000..e35a248 --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTLegendEntry.h @@ -0,0 +1,40 @@ +#import "CPTDefinitions.h" +#import +#import + +@class CPTPlot; +@class CPTTextStyle; + +@interface CPTLegendEntry : NSObject { + @private + __cpt_weak CPTPlot *plot; + NSUInteger index; + NSUInteger row; + NSUInteger column; + CPTTextStyle *textStyle; +} + +/// @name Plot Info +/// @{ +@property (nonatomic, readwrite, cpt_weak_property) __cpt_weak CPTPlot *plot; +@property (nonatomic, readwrite, assign) NSUInteger index; +/// @} + +/// @name Formatting +/// @{ +@property (nonatomic, readwrite, retain) CPTTextStyle *textStyle; +/// @} + +/// @name Layout +/// @{ +@property (nonatomic, readwrite, assign) NSUInteger row; +@property (nonatomic, readwrite, assign) NSUInteger column; +@property (nonatomic, readonly, assign) CGSize titleSize; +/// @} + +/// @name Drawing +/// @{ +-(void)drawTitleInRect:(CGRect)rect inContext:(CGContextRef)context scale:(CGFloat)scale; +/// @} + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTLimitBand.h b/CorePlot.framework/Versions/A/Headers/CPTLimitBand.h new file mode 100644 index 0000000..f932e9a --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTLimitBand.h @@ -0,0 +1,25 @@ +#import + +@class CPTPlotRange; +@class CPTFill; + +@interface CPTLimitBand : NSObject { + @private + CPTPlotRange *range; + CPTFill *fill; +} + +@property (nonatomic, readwrite, retain) CPTPlotRange *range; +@property (nonatomic, readwrite, retain) CPTFill *fill; + +/// @name Factory Methods +/// @{ ++(CPTLimitBand *)limitBandWithRange:(CPTPlotRange *)newRange fill:(CPTFill *)newFill; +/// @} + +/// @name Initialization +/// @{ +-(id)initWithRange:(CPTPlotRange *)newRange fill:(CPTFill *)newFill; +/// @} + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTLineCap.h b/CorePlot.framework/Versions/A/Headers/CPTLineCap.h new file mode 100644 index 0000000..037f133 --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTLineCap.h @@ -0,0 +1,69 @@ +#import +#import + +/// @file + +@class CPTLineStyle; +@class CPTFill; + +/** + * @brief Line cap types. + **/ +typedef enum _CPTLineCapType { + CPTLineCapTypeNone, ///< No line cap. + CPTLineCapTypeOpenArrow, ///< Open arrow line cap. + CPTLineCapTypeSolidArrow, ///< Solid arrow line cap. + CPTLineCapTypeSweptArrow, ///< Swept arrow line cap. + CPTLineCapTypeRectangle, ///< Rectangle line cap. + CPTLineCapTypeEllipse, ///< Elliptical line cap. + CPTLineCapTypeDiamond, ///< Diamond line cap. + CPTLineCapTypePentagon, ///< Pentagon line cap. + CPTLineCapTypeHexagon, ///< Hexagon line cap. + CPTLineCapTypeBar, ///< Bar line cap. + CPTLineCapTypeCross, ///< X line cap. + CPTLineCapTypeSnow, ///< Snowflake line cap. + CPTLineCapTypeCustom ///< Custom line cap. +} +CPTLineCapType; + +@interface CPTLineCap : NSObject { + @private + CGSize size; + CPTLineCapType lineCapType; + CPTLineStyle *lineStyle; + CPTFill *fill; + CGPathRef cachedLineCapPath; + CGPathRef customLineCapPath; + BOOL usesEvenOddClipRule; +} + +@property (nonatomic, readwrite, assign) CGSize size; +@property (nonatomic, readwrite, assign) CPTLineCapType lineCapType; +@property (nonatomic, readwrite, retain) CPTLineStyle *lineStyle; +@property (nonatomic, readwrite, retain) CPTFill *fill; +@property (nonatomic, readwrite, assign) CGPathRef customLineCapPath; +@property (nonatomic, readwrite, assign) BOOL usesEvenOddClipRule; + +/// @name Factory Methods +/// @{ ++(CPTLineCap *)lineCap; ++(CPTLineCap *)openArrowPlotLineCap; ++(CPTLineCap *)solidArrowPlotLineCap; ++(CPTLineCap *)sweptArrowPlotLineCap; ++(CPTLineCap *)rectanglePlotLineCap; ++(CPTLineCap *)ellipsePlotLineCap; ++(CPTLineCap *)diamondPlotLineCap; ++(CPTLineCap *)pentagonPlotLineCap; ++(CPTLineCap *)hexagonPlotLineCap; ++(CPTLineCap *)barPlotLineCap; ++(CPTLineCap *)crossPlotLineCap; ++(CPTLineCap *)snowPlotLineCap; ++(CPTLineCap *)customLineCapWithPath:(CGPathRef)aPath; +/// @} + +/// @name Drawing +/// @{ +-(void)renderAsVectorInContext:(CGContextRef)theContext atPoint:(CGPoint)center inDirection:(CGPoint)direction; +/// @} + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTLineStyle.h b/CorePlot.framework/Versions/A/Headers/CPTLineStyle.h new file mode 100644 index 0000000..66202fa --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTLineStyle.h @@ -0,0 +1,37 @@ +#import +#import + +@class CPTColor; + +@interface CPTLineStyle : NSObject { + @private + CGLineCap lineCap; +// CGLineDash lineDash; // We should make a struct to keep this information + CGLineJoin lineJoin; + CGFloat miterLimit; + CGFloat lineWidth; + NSArray *dashPattern; + CGFloat patternPhase; +// StrokePattern; // We should make a struct to keep this information + CPTColor *lineColor; +} + +@property (nonatomic, readonly, assign) CGLineCap lineCap; +@property (nonatomic, readonly, assign) CGLineJoin lineJoin; +@property (nonatomic, readonly, assign) CGFloat miterLimit; +@property (nonatomic, readonly, assign) CGFloat lineWidth; +@property (nonatomic, readonly, retain) NSArray *dashPattern; +@property (nonatomic, readonly, assign) CGFloat patternPhase; +@property (nonatomic, readonly, retain) CPTColor *lineColor; + +/// @name Factory Methods +/// @{ ++(id)lineStyle; +/// @} + +/// @name Drawing +/// @{ +-(void)setLineStyleInContext:(CGContextRef)theContext; +/// @} + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTMutableLineStyle.h b/CorePlot.framework/Versions/A/Headers/CPTMutableLineStyle.h new file mode 100644 index 0000000..a740394 --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTMutableLineStyle.h @@ -0,0 +1,17 @@ +#import "CPTLineStyle.h" +#import + +@class CPTColor; + +@interface CPTMutableLineStyle : CPTLineStyle { +} + +@property (nonatomic, readwrite, assign) CGLineCap lineCap; +@property (nonatomic, readwrite, assign) CGLineJoin lineJoin; +@property (nonatomic, readwrite, assign) CGFloat miterLimit; +@property (nonatomic, readwrite, assign) CGFloat lineWidth; +@property (nonatomic, readwrite, retain) NSArray *dashPattern; +@property (nonatomic, readwrite, assign) CGFloat patternPhase; +@property (nonatomic, readwrite, retain) CPTColor *lineColor; + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTMutableNumericData+TypeConversion.h b/CorePlot.framework/Versions/A/Headers/CPTMutableNumericData+TypeConversion.h new file mode 100644 index 0000000..f762c3e --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTMutableNumericData+TypeConversion.h @@ -0,0 +1,23 @@ +#import "CPTMutableNumericData.h" +#import "CPTNumericDataType.h" +#import + +/** @category CPTMutableNumericData(TypeConversion) + * @brief Type conversion methods for CPTMutableNumericData. + **/ +@interface CPTMutableNumericData(TypeConversion) + +/// @name Data Format +/// @{ +@property (assign, readwrite) CPTNumericDataType dataType; +@property (assign, readwrite) CPTDataTypeFormat dataTypeFormat; +@property (assign, readwrite) size_t sampleBytes; +@property (assign, readwrite) CFByteOrder byteOrder; +/// @} + +/// @name Type Conversion +/// @{ +-(void)convertToType:(CPTDataTypeFormat)newDataType sampleBytes:(size_t)newSampleBytes byteOrder:(CFByteOrder)newByteOrder; +/// @} + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTMutableNumericData.h b/CorePlot.framework/Versions/A/Headers/CPTMutableNumericData.h new file mode 100644 index 0000000..3e25674 --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTMutableNumericData.h @@ -0,0 +1,29 @@ +#import "CPTNumericData.h" +#import "CPTNumericDataType.h" +#import + +@interface CPTMutableNumericData : CPTNumericData { +} + +/// @name Data Buffer +/// @{ +@property (readonly) void *mutableBytes; +/// @} + +/// @name Dimensions +/// @{ +@property (copy, readwrite) NSArray *shape; +/// @} + +/// @name Factory Methods +/// @{ ++(CPTMutableNumericData *)numericDataWithData:(NSData *)newData dataType:(CPTNumericDataType)newDataType shape:(NSArray *)shapeArray; ++(CPTMutableNumericData *)numericDataWithData:(NSData *)newData dataTypeString:(NSString *)newDataTypeString shape:(NSArray *)shapeArray; +/// @} + +/// @name Initialization +/// @{ +-(id)initWithData:(NSData *)newData dataType:(CPTNumericDataType)newDataType shape:(NSArray *)shapeArray; +/// @} + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTMutablePlotRange.h b/CorePlot.framework/Versions/A/Headers/CPTMutablePlotRange.h new file mode 100644 index 0000000..8687af4 --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTMutablePlotRange.h @@ -0,0 +1,29 @@ +#import "CPTPlotRange.h" + +@interface CPTMutablePlotRange : CPTPlotRange { +} + +/// @name Range Limits +/// @{ +@property (nonatomic, readwrite) NSDecimal location; +@property (nonatomic, readwrite) NSDecimal length; +/// @} + +/// @name Combining Ranges +/// @{ +-(void)unionPlotRange:(CPTPlotRange *)otherRange; +-(void)intersectionPlotRange:(CPTPlotRange *)otherRange; +/// @} + +/// @name Shifting Ranges +/// @{ +-(void)shiftLocationToFitInRange:(CPTPlotRange *)otherRange; +-(void)shiftEndToFitInRange:(CPTPlotRange *)otherRange; +/// @} + +/// @name Expanding/Contracting Ranges +/// @{ +-(void)expandRangeByFactor:(NSDecimal)factor; +/// @} + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTMutableShadow.h b/CorePlot.framework/Versions/A/Headers/CPTMutableShadow.h new file mode 100644 index 0000000..064cb5d --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTMutableShadow.h @@ -0,0 +1,14 @@ +#import "CPTShadow.h" +#import +#import + +@class CPTColor; + +@interface CPTMutableShadow : CPTShadow { +} + +@property (nonatomic, readwrite, assign) CGSize shadowOffset; +@property (nonatomic, readwrite, assign) CGFloat shadowBlurRadius; +@property (nonatomic, readwrite, retain) CPTColor *shadowColor; + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTMutableTextStyle.h b/CorePlot.framework/Versions/A/Headers/CPTMutableTextStyle.h new file mode 100644 index 0000000..07fbdfe --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTMutableTextStyle.h @@ -0,0 +1,14 @@ +#import "CPTTextStyle.h" +#import + +@class CPTColor; + +@interface CPTMutableTextStyle : CPTTextStyle { +} + +@property (readwrite, copy, nonatomic) NSString *fontName; +@property (readwrite, assign, nonatomic) CGFloat fontSize; +@property (readwrite, copy, nonatomic) CPTColor *color; +@property (readwrite, assign, nonatomic) CPTTextAlignment textAlignment; + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTNumericData+TypeConversion.h b/CorePlot.framework/Versions/A/Headers/CPTNumericData+TypeConversion.h new file mode 100644 index 0000000..1752594 --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTNumericData+TypeConversion.h @@ -0,0 +1,23 @@ +#import "CPTNumericData.h" +#import "CPTNumericDataType.h" +#import + +/** @category CPTNumericData(TypeConversion) + * @brief Type conversion methods for CPTNumericData. + **/ +@interface CPTNumericData(TypeConversion) + +/// @name Type Conversion +/// @{ +-(CPTNumericData *)dataByConvertingToDataType:(CPTNumericDataType)newDataType; + +-(CPTNumericData *)dataByConvertingToType:(CPTDataTypeFormat)newDataType sampleBytes:(size_t)newSampleBytes byteOrder:(CFByteOrder)newByteOrder; +/// @} + +/// @name Data Conversion Utilities +/// @{ +-(void)convertData:(NSData *)sourceData dataType:(CPTNumericDataType *)sourceDataType toData:(NSMutableData *)destData dataType:(CPTNumericDataType *)destDataType; +-(void)swapByteOrderForData:(NSMutableData *)sourceData sampleSize:(size_t)sampleSize; +/// @} + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTNumericData.h b/CorePlot.framework/Versions/A/Headers/CPTNumericData.h new file mode 100644 index 0000000..d36b77f --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTNumericData.h @@ -0,0 +1,56 @@ +#import "CPTNumericDataType.h" +#import + +@interface CPTNumericData : NSObject { + @protected + NSData *data; + CPTNumericDataType dataType; + NSArray *shape; // array of dimension shapes (NSNumber) +} + +/// @name Data Buffer +/// @{ +@property (copy, readonly) NSData *data; +@property (readonly) const void *bytes; +@property (readonly) NSUInteger length; +/// @} + +/// @name Data Format +/// @{ +@property (assign, readonly) CPTNumericDataType dataType; +@property (readonly) CPTDataTypeFormat dataTypeFormat; +@property (readonly) size_t sampleBytes; +@property (readonly) CFByteOrder byteOrder; +/// @} + +/// @name Dimensions +/// @{ +@property (copy, readonly) NSArray *shape; +@property (readonly) NSUInteger numberOfDimensions; +@property (readonly) NSUInteger numberOfSamples; +/// @} + +/// @name Factory Methods +/// @{ ++(CPTNumericData *)numericDataWithData:(NSData *)newData dataType:(CPTNumericDataType)newDataType shape:(NSArray *)shapeArray; ++(CPTNumericData *)numericDataWithData:(NSData *)newData dataTypeString:(NSString *)newDataTypeString shape:(NSArray *)shapeArray; ++(CPTNumericData *)numericDataWithArray:(NSArray *)newData dataType:(CPTNumericDataType)newDataType shape:(NSArray *)shapeArray; ++(CPTNumericData *)numericDataWithArray:(NSArray *)newData dataTypeString:(NSString *)newDataTypeString shape:(NSArray *)shapeArray; +/// @} + +/// @name Initialization +/// @{ +-(id)initWithData:(NSData *)newData dataType:(CPTNumericDataType)newDataType shape:(NSArray *)shapeArray; +-(id)initWithData:(NSData *)newData dataTypeString:(NSString *)newDataTypeString shape:(NSArray *)shapeArray; +-(id)initWithArray:(NSArray *)newData dataType:(CPTNumericDataType)newDataType shape:(NSArray *)shapeArray; +-(id)initWithArray:(NSArray *)newData dataTypeString:(NSString *)newDataTypeString shape:(NSArray *)shapeArray; +/// @} + +/// @name Samples +/// @{ +-(void *)samplePointer:(NSUInteger)sample; +-(NSNumber *)sampleValue:(NSUInteger)sample; +-(NSArray *)sampleArray; +/// @} + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTNumericDataType.h b/CorePlot.framework/Versions/A/Headers/CPTNumericDataType.h new file mode 100644 index 0000000..2ef8950 --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTNumericDataType.h @@ -0,0 +1,44 @@ +#import + +/// @file + +/** + * @brief Enumeration of data formats for numeric data. + **/ +typedef enum _CPTDataTypeFormat { + CPTUndefinedDataType = 0, ///< Undefined + CPTIntegerDataType, ///< Integer + CPTUnsignedIntegerDataType, ///< Unsigned integer + CPTFloatingPointDataType, ///< Floating point + CPTComplexFloatingPointDataType, ///< Complex floating point + CPTDecimalDataType ///< NSDecimal +} +CPTDataTypeFormat; + +/** + * @brief Struct that describes the encoding of numeric data samples. + **/ +typedef struct _CPTNumericDataType { + CPTDataTypeFormat dataTypeFormat; ///< Data type format + size_t sampleBytes; ///< Number of bytes in each sample + CFByteOrder byteOrder; ///< Byte order +} +CPTNumericDataType; + +#if __cplusplus +extern "C" { +#endif + +/// @name Data Type Utilities +/// @{ +CPTNumericDataType CPTDataType(CPTDataTypeFormat format, size_t sampleBytes, CFByteOrder byteOrder); +CPTNumericDataType CPTDataTypeWithDataTypeString(NSString *dataTypeString); +NSString *CPTDataTypeStringFromDataType(CPTNumericDataType dataType); +BOOL CPTDataTypeIsSupported(CPTNumericDataType format); +BOOL CPTDataTypeEqualToDataType(CPTNumericDataType dataType1, CPTNumericDataType dataType2); + +/// @} + +#if __cplusplus +} +#endif diff --git a/CorePlot.framework/Versions/A/Headers/CPTPathExtensions.h b/CorePlot.framework/Versions/A/Headers/CPTPathExtensions.h new file mode 100644 index 0000000..3d3e328 --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTPathExtensions.h @@ -0,0 +1,15 @@ +#import +#import + +/// @file + +#if __cplusplus +extern "C" { +#endif + +CGPathRef CreateRoundedRectPath(CGRect rect, CGFloat cornerRadius); +void AddRoundedRectPath(CGContextRef context, CGRect rect, CGFloat cornerRadius); + +#if __cplusplus +} +#endif diff --git a/CorePlot.framework/Versions/A/Headers/CPTPieChart.h b/CorePlot.framework/Versions/A/Headers/CPTPieChart.h new file mode 100644 index 0000000..908b63c --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTPieChart.h @@ -0,0 +1,132 @@ +#import "CPTDefinitions.h" +#import "CPTPlot.h" +#import + +/// @file + +@class CPTColor; +@class CPTFill; +@class CPTMutableNumericData; +@class CPTNumericData; +@class CPTPieChart; +@class CPTTextLayer; +@class CPTLineStyle; + +/// @ingroup plotBindingsPieChart +/// @{ +extern NSString *const CPTPieChartBindingPieSliceWidthValues; +/// @} + +/** + * @brief Enumeration of pie chart data source field types. + **/ +typedef enum _CPTPieChartField { + CPTPieChartFieldSliceWidth, ///< Pie slice width. + CPTPieChartFieldSliceWidthNormalized, ///< Pie slice width normalized [0, 1]. + CPTPieChartFieldSliceWidthSum ///< Cumulative sum of pie slice widths. +} +CPTPieChartField; + +/** + * @brief Enumeration of pie slice drawing directions. + **/ +typedef enum _CPTPieDirection { + CPTPieDirectionClockwise, ///< Pie slices are drawn in a clockwise direction. + CPTPieDirectionCounterClockwise ///< Pie slices are drawn in a counter-clockwise direction. +} +CPTPieDirection; + +#pragma mark - + +/** + * @brief A pie chart data source. + **/ +@protocol CPTPieChartDataSource +@optional + +/// @name Slice Style +/// @{ + +/** @brief (Optional) Gets a fill for the given pie chart slice. + * @param pieChart The pie chart. + * @param index The data index of interest. + * @return The pie slice fill for the slice with the given index. + **/ +-(CPTFill *)sliceFillForPieChart:(CPTPieChart *)pieChart recordIndex:(NSUInteger)index; + +/// @} + +/// @name Slice Layout +/// @{ + +/** @brief (Optional) Offsets the slice radially from the center point. Can be used to "explode" the chart. + * @param pieChart The pie chart. + * @param index The data index of interest. + * @return The radial offset in view coordinates. Zero is no offset. + **/ +-(CGFloat)radialOffsetForPieChart:(CPTPieChart *)pieChart recordIndex:(NSUInteger)index; + +/// @{ + +/// @name Legends +/// @{ + +/** @brief (Optional) Gets the legend title for the given pie chart slice. + * @param pieChart The pie chart. + * @param index The data index of interest. + * @return The title text for the legend entry for the point with the given index. + **/ +-(NSString *)legendTitleForPieChart:(CPTPieChart *)pieChart recordIndex:(NSUInteger)index; + +/// @} +@end + +#pragma mark - + +/** + * @brief Pie chart delegate. + **/ +@protocol CPTPieChartDelegate + +@optional + +/// @name Point Selection +/// @{ + +/** @brief (Optional) Informs the delegate that a pie slice was touched or clicked. + * @param plot The pie chart. + * @param index The index of the slice that was touched or clicked. + **/ +-(void)pieChart:(CPTPieChart *)plot sliceWasSelectedAtRecordIndex:(NSUInteger)index; + +/// @} + +@end + +#pragma mark - + +@interface CPTPieChart : CPTPlot { + @private + CGFloat pieRadius; + CGFloat pieInnerRadius; + CGFloat startAngle; + CPTPieDirection sliceDirection; + CGPoint centerAnchor; + CPTLineStyle *borderLineStyle; + CPTFill *overlayFill; +} + +@property (nonatomic, readwrite) CGFloat pieRadius; +@property (nonatomic, readwrite) CGFloat pieInnerRadius; +@property (nonatomic, readwrite) CGFloat startAngle; +@property (nonatomic, readwrite) CPTPieDirection sliceDirection; +@property (nonatomic, readwrite) CGPoint centerAnchor; +@property (nonatomic, readwrite, copy) CPTLineStyle *borderLineStyle; +@property (nonatomic, readwrite, copy) CPTFill *overlayFill; + +/// @name Factory Methods +/// @{ ++(CPTColor *)defaultPieSliceColorForIndex:(NSUInteger)pieSliceIndex; +/// @} + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTPlatformSpecificCategories.h b/CorePlot.framework/Versions/A/Headers/CPTPlatformSpecificCategories.h new file mode 100644 index 0000000..141cca1 --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTPlatformSpecificCategories.h @@ -0,0 +1,26 @@ +#import "CPTColor.h" +#import "CPTLayer.h" +#import "CPTPlatformSpecificDefines.h" +#import +#import + +/** @category CPTLayer(CPTPlatformSpecificLayerExtensions) + * @brief Platform-specific extensions to CPTLayer. + **/ +@interface CPTLayer(CPTPlatformSpecificLayerExtensions) + +/// @name Images +/// @{ +-(CPTNativeImage *)imageOfLayer; +/// @} + +@end + +/** @category CPTColor(CPTPlatformSpecificColorExtensions) + * @brief Platform-specific extensions to CPTColor. + **/ +@interface CPTColor(CPTPlatformSpecificColorExtensions) + +@property (nonatomic, readonly, retain) NSColor *nsColor; + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTPlatformSpecificDefines.h b/CorePlot.framework/Versions/A/Headers/CPTPlatformSpecificDefines.h new file mode 100644 index 0000000..49ad5dc --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTPlatformSpecificDefines.h @@ -0,0 +1,6 @@ +#import +#import + +/// @file + +typedef NSImage CPTNativeImage; ///< Platform-native image format. diff --git a/CorePlot.framework/Versions/A/Headers/CPTPlatformSpecificFunctions.h b/CorePlot.framework/Versions/A/Headers/CPTPlatformSpecificFunctions.h new file mode 100644 index 0000000..6f2c98a --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTPlatformSpecificFunctions.h @@ -0,0 +1,33 @@ +#import "CPTDefinitions.h" +#import +#import + +/// @file + +#if __cplusplus +extern "C" { +#endif + +/// @name Graphics Context Save Stack +/// @{ +void CPTPushCGContext(CGContextRef context); +void CPTPopCGContext(void); + +/// @} + +/// @name Graphics Context +/// @{ +CGContextRef CPTGetCurrentContext(void); + +/// @} + +/// @name Color Conversion +/// @{ +CGColorRef CPTCreateCGColorFromNSColor(NSColor *nsColor); +CPTRGBAColor CPTRGBAColorFromNSColor(NSColor *nsColor); + +/// @} + +#if __cplusplus +} +#endif diff --git a/CorePlot.framework/Versions/A/Headers/CPTPlot.h b/CorePlot.framework/Versions/A/Headers/CPTPlot.h new file mode 100644 index 0000000..29d7908 --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTPlot.h @@ -0,0 +1,249 @@ +#import "CPTAnnotationHostLayer.h" +#import "CPTDefinitions.h" +#import "CPTMutableTextStyle.h" +#import "CPTNumericDataType.h" +#import "CPTPlotRange.h" + +@class CPTLegend; +@class CPTMutableNumericData; +@class CPTNumericData; +@class CPTPlot; +@class CPTPlotArea; +@class CPTPlotSpace; +@class CPTPlotSpaceAnnotation; +@class CPTPlotRange; + +/// @file + +/** + * @brief Enumeration of cache precisions. + **/ +typedef enum _CPTPlotCachePrecision { + CPTPlotCachePrecisionAuto, ///< Cache precision is determined automatically from the data. All cached data will be converted to match the last data loaded. + CPTPlotCachePrecisionDouble, ///< All cached data will be converted to double precision. + CPTPlotCachePrecisionDecimal ///< All cached data will be converted to NSDecimal. +} +CPTPlotCachePrecision; + +#pragma mark - + +/** + * @brief A plot data source. + **/ +@protocol CPTPlotDataSource + +/// @name Data Values +/// @{ + +/** @brief (Required) The number of data points for the plot. + * @param plot The plot. + * @return The number of data points for the plot. + **/ +-(NSUInteger)numberOfRecordsForPlot:(CPTPlot *)plot; + +@optional + +/** @brief (Optional) Gets a range of plot data for the given plot and field. + * Implement one and only one of the optional methods in this section. + * @param plot The plot. + * @param fieldEnum The field index. + * @param indexRange The range of the data indexes of interest. + * @return An array of data points. + **/ +-(NSArray *)numbersForPlot:(CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndexRange:(NSRange)indexRange; + +/** @brief (Optional) Gets a plot data value for the given plot and field. + * Implement one and only one of the optional methods in this section. + * @param plot The plot. + * @param fieldEnum The field index. + * @param index The data index of interest. + * @return A data point. + **/ +-(NSNumber *)numberForPlot:(CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index; + +/** @brief (Optional) Gets a range of plot data for the given plot and field. + * Implement one and only one of the optional methods in this section. + * @param plot The plot. + * @param fieldEnum The field index. + * @param indexRange The range of the data indexes of interest. + * @return A retained C array of data points. + **/ +-(double *)doublesForPlot:(CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndexRange:(NSRange)indexRange; + +/** @brief (Optional) Gets a plot data value for the given plot and field. + * Implement one and only one of the optional methods in this section. + * @param plot The plot. + * @param fieldEnum The field index. + * @param index The data index of interest. + * @return A data point. + **/ +-(double)doubleForPlot:(CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index; + +/** @brief (Optional) Gets a range of plot data for the given plot and field. + * Implement one and only one of the optional methods in this section. + * @param plot The plot. + * @param fieldEnum The field index. + * @param indexRange The range of the data indexes of interest. + * @return A one-dimensional array of data points. + **/ +-(CPTNumericData *)dataForPlot:(CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndexRange:(NSRange)indexRange; + +/// @} + +/// @name Data Labels +/// @{ + +/** @brief (Optional) Gets a data label for the given plot. + * @param plot The plot. + * @param index The data index of interest. + * @return The data label for the point with the given index. + * If you return nil, the default data label will be used. If you return an instance of NSNull, + * no label will be shown for the index in question. + **/ +-(CPTLayer *)dataLabelForPlot:(CPTPlot *)plot recordIndex:(NSUInteger)index; + +/// @} + +@end + +#pragma mark - + +@interface CPTPlot : CPTAnnotationHostLayer { + @private + __cpt_weak id dataSource; + NSString *title; + CPTPlotSpace *plotSpace; + BOOL dataNeedsReloading; + NSMutableDictionary *cachedData; + NSUInteger cachedDataCount; + CPTPlotCachePrecision cachePrecision; + BOOL needsRelabel; + CGFloat labelOffset; + CGFloat labelRotation; + NSUInteger labelField; + CPTTextStyle *labelTextStyle; + NSNumberFormatter *labelFormatter; + NSRange labelIndexRange; + NSMutableArray *labelAnnotations; + CPTShadow *labelShadow; + BOOL alignsPointsToPixels; +} + +/// @name Data Source +/// @{ +@property (nonatomic, readwrite, cpt_weak_property) __cpt_weak id dataSource; +/// @} + +/// @name Identification +/// @{ +@property (nonatomic, readwrite, copy) NSString *title; +/// @} + +/// @name Plot Space +/// @{ +@property (nonatomic, readwrite, retain) CPTPlotSpace *plotSpace; +/// @} + +/// @name Plot Area +/// @{ +@property (nonatomic, readonly, retain) CPTPlotArea *plotArea; +/// @} + +/// @name Data Loading +/// @{ +@property (nonatomic, readonly, assign) BOOL dataNeedsReloading; +/// @} + +/// @name Data Cache +/// @{ +@property (nonatomic, readonly, assign) NSUInteger cachedDataCount; +@property (nonatomic, readonly, assign) BOOL doublePrecisionCache; +@property (nonatomic, readwrite, assign) CPTPlotCachePrecision cachePrecision; +@property (nonatomic, readonly, assign) CPTNumericDataType doubleDataType; +@property (nonatomic, readonly, assign) CPTNumericDataType decimalDataType; +/// @} + +/// @name Data Labels +/// @{ +@property (nonatomic, readonly, assign) BOOL needsRelabel; +@property (nonatomic, readwrite, assign) CGFloat labelOffset; +@property (nonatomic, readwrite, assign) CGFloat labelRotation; +@property (nonatomic, readwrite, assign) NSUInteger labelField; +@property (nonatomic, readwrite, copy) CPTTextStyle *labelTextStyle; +@property (nonatomic, readwrite, retain) NSNumberFormatter *labelFormatter; +@property (nonatomic, readwrite, retain) CPTShadow *labelShadow; +/// @} + +/// @name Drawing +/// @{ +@property (nonatomic, readwrite, assign) BOOL alignsPointsToPixels; +/// @} + +/// @name Data Labels +/// @{ +-(void)setNeedsRelabel; +-(void)relabel; +-(void)relabelIndexRange:(NSRange)indexRange; +-(void)repositionAllLabelAnnotations; +/// @} + +/// @name Data Loading +/// @{ +-(void)setDataNeedsReloading; +-(void)reloadData; +-(void)reloadDataIfNeeded; +-(void)reloadDataInIndexRange:(NSRange)indexRange; +-(void)insertDataAtIndex:(NSUInteger)index numberOfRecords:(NSUInteger)numberOfRecords; +-(void)deleteDataInIndexRange:(NSRange)indexRange; +/// @} + +/// @name Plot Data +/// @{ +-(id)numbersFromDataSourceForField:(NSUInteger)fieldEnum recordIndexRange:(NSRange)indexRange; +/// @} + +/// @name Data Cache +/// @{ +-(CPTMutableNumericData *)cachedNumbersForField:(NSUInteger)fieldEnum; +-(NSNumber *)cachedNumberForField:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index; +-(double)cachedDoubleForField:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index; +-(NSDecimal)cachedDecimalForField:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index; +-(void)cacheNumbers:(id)numbers forField:(NSUInteger)fieldEnum; +-(void)cacheNumbers:(id)numbers forField:(NSUInteger)fieldEnum atRecordIndex:(NSUInteger)index; +/// @} + +/// @name Plot Data Ranges +/// @{ +-(CPTPlotRange *)plotRangeForField:(NSUInteger)fieldEnum; +-(CPTPlotRange *)plotRangeForCoordinate:(CPTCoordinate)coord; +/// @} + +/// @name Legends +/// @{ +-(NSUInteger)numberOfLegendEntries; +-(NSString *)titleForLegendEntryAtIndex:(NSUInteger)index; +-(void)drawSwatchForLegend:(CPTLegend *)legend atIndex:(NSUInteger)index inRect:(CGRect)rect inContext:(CGContextRef)context; +/// @} + +@end + +#pragma mark - + +/** @category CPTPlot(AbstractMethods) + * @brief CPTPlot abstract methods—must be overridden by subclasses + **/ +@interface CPTPlot(AbstractMethods) + +/// @name Fields +/// @{ +-(NSUInteger)numberOfFields; +-(NSArray *)fieldIdentifiers; +-(NSArray *)fieldIdentifiersForCoordinate:(CPTCoordinate)coord; +/// @} + +/// @name Data Labels +/// @{ +-(void)positionLabelAnnotation:(CPTPlotSpaceAnnotation *)label forIndex:(NSUInteger)index; +/// @} + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTPlotArea.h b/CorePlot.framework/Versions/A/Headers/CPTPlotArea.h new file mode 100644 index 0000000..d920f99 --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTPlotArea.h @@ -0,0 +1,56 @@ +#import "CPTAnnotationHostLayer.h" +#import "CPTGraph.h" +#import "CPTLayer.h" +#import + +@class CPTAxis; +@class CPTAxisLabelGroup; +@class CPTAxisSet; +@class CPTGridLineGroup; +@class CPTPlotGroup; +@class CPTLineStyle; +@class CPTFill; + +@interface CPTPlotArea : CPTAnnotationHostLayer { + @private + CPTGridLineGroup *minorGridLineGroup; + CPTGridLineGroup *majorGridLineGroup; + CPTAxisSet *axisSet; + CPTPlotGroup *plotGroup; + CPTAxisLabelGroup *axisLabelGroup; + CPTAxisLabelGroup *axisTitleGroup; + CPTFill *fill; + NSArray *topDownLayerOrder; + CPTGraphLayerType *bottomUpLayerOrder; + BOOL updatingLayers; +} + +/// @name Layers +/// @{ +@property (nonatomic, readwrite, retain) CPTGridLineGroup *minorGridLineGroup; +@property (nonatomic, readwrite, retain) CPTGridLineGroup *majorGridLineGroup; +@property (nonatomic, readwrite, retain) CPTAxisSet *axisSet; +@property (nonatomic, readwrite, retain) CPTPlotGroup *plotGroup; +@property (nonatomic, readwrite, retain) CPTAxisLabelGroup *axisLabelGroup; +@property (nonatomic, readwrite, retain) CPTAxisLabelGroup *axisTitleGroup; +/// @} + +/// @name Layer Ordering +/// @{ +@property (nonatomic, readwrite, retain) NSArray *topDownLayerOrder; +/// @} + +/// @name Decorations +/// @{ +@property (nonatomic, readwrite, copy) CPTLineStyle *borderLineStyle; +@property (nonatomic, readwrite, copy) CPTFill *fill; +/// @} + +/// @name Axis Set Layer Management +/// @{ +-(void)updateAxisSetLayersForType:(CPTGraphLayerType)layerType; +-(void)setAxisSetLayersForType:(CPTGraphLayerType)layerType; +-(unsigned)sublayerIndexForAxis:(CPTAxis *)axis layerType:(CPTGraphLayerType)layerType; +/// @} + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTPlotAreaFrame.h b/CorePlot.framework/Versions/A/Headers/CPTPlotAreaFrame.h new file mode 100644 index 0000000..7a2cbed --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTPlotAreaFrame.h @@ -0,0 +1,16 @@ +#import "CPTBorderedLayer.h" + +@class CPTAxisSet; +@class CPTPlotGroup; +@class CPTPlotArea; + +@interface CPTPlotAreaFrame : CPTBorderedLayer { + @private + CPTPlotArea *plotArea; +} + +@property (nonatomic, readonly, retain) CPTPlotArea *plotArea; +@property (nonatomic, readwrite, retain) CPTAxisSet *axisSet; +@property (nonatomic, readwrite, retain) CPTPlotGroup *plotGroup; + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTPlotRange.h b/CorePlot.framework/Versions/A/Headers/CPTPlotRange.h new file mode 100644 index 0000000..d787a3d --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTPlotRange.h @@ -0,0 +1,65 @@ +#import "CPTDefinitions.h" +#import + +/// @file + +/** + * @brief Enumeration of possible results of a plot range comparison. + **/ +typedef enum _CPTPlotRangeComparisonResult { + CPTPlotRangeComparisonResultNumberBelowRange, ///< Number is below the range. + CPTPlotRangeComparisonResultNumberInRange, ///< Number is in the range. + CPTPlotRangeComparisonResultNumberAboveRange ///< Number is above the range. +} +CPTPlotRangeComparisonResult; + +@interface CPTPlotRange : NSObject { + @private + NSDecimal location; + NSDecimal length; + double locationDouble; + double lengthDouble; +} + +/// @name Range Limits +/// @{ +@property (nonatomic, readonly) NSDecimal location; +@property (nonatomic, readonly) NSDecimal length; +@property (nonatomic, readonly) NSDecimal end; +@property (nonatomic, readonly) double locationDouble; +@property (nonatomic, readonly) double lengthDouble; +@property (nonatomic, readonly) double endDouble; + +@property (nonatomic, readonly) NSDecimal minLimit; +@property (nonatomic, readonly) NSDecimal midPoint; +@property (nonatomic, readonly) NSDecimal maxLimit; +@property (nonatomic, readonly) double minLimitDouble; +@property (nonatomic, readonly) double midPointDouble; +@property (nonatomic, readonly) double maxLimitDouble; +/// @} + +/// @name Factory Methods +/// @{ ++(id)plotRangeWithLocation:(NSDecimal)loc length:(NSDecimal)len; +/// @} + +/// @name Initialization +/// @{ +-(id)initWithLocation:(NSDecimal)loc length:(NSDecimal)len; +/// @} + +/// @name Checking Ranges +/// @{ +-(BOOL)contains:(NSDecimal)number; +-(BOOL)containsDouble:(double)number; +-(BOOL)isEqualToRange:(CPTPlotRange *)otherRange; +/// @} + +/// @name Range Comparison +/// @{ +-(CPTPlotRangeComparisonResult)compareToNumber:(NSNumber *)number; +-(CPTPlotRangeComparisonResult)compareToDecimal:(NSDecimal)number; +-(CPTPlotRangeComparisonResult)compareToDouble:(double)number; +/// @} + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTPlotSpace.h b/CorePlot.framework/Versions/A/Headers/CPTPlotSpace.h new file mode 100644 index 0000000..e84dd21 --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTPlotSpace.h @@ -0,0 +1,166 @@ +#import "CPTDefinitions.h" +#import "CPTResponder.h" + +@class CPTLayer; +@class CPTPlotRange; +@class CPTGraph; +@class CPTPlotSpace; + +/// @name Plot Space +/// @{ + +/** @brief Plot space coordinate change notification. + * + * This notification is posted to the default notification center whenever the mapping between + * the plot space coordinate system and drawing coordinates changes. + * @ingroup notification + **/ +extern NSString *const CPTPlotSpaceCoordinateMappingDidChangeNotification; + +/// @} + +/** + * @brief Plot space delegate. + **/ +@protocol CPTPlotSpaceDelegate + +@optional + +/// @name Scaling +/// @{ + +/** @brief (Optional) Informs the receiver that it should uniformly scale (e.g., in response to a pinch on iOS). + * @param space The plot space. + * @param interactionScale The scaling factor. + * @param interactionPoint The coordinates of the scaling centroid. + * @return YES should be returned if the gesture should be handled by the plot space, and NO to prevent handling. + * In either case, the delegate may choose to take extra actions, or handle the scaling itself. + **/ +-(BOOL)plotSpace:(CPTPlotSpace *)space shouldScaleBy:(CGFloat)interactionScale aboutPoint:(CGPoint)interactionPoint; + +/// @} + +/// @name Scrolling +/// @{ + +/** @brief (Optional) Notifies that plot space is going to scroll. + * @param space The plot space. + * @param proposedDisplacementVector The proposed amount by which the plot space will shift. + * @return The displacement actually applied. + **/ +-(CGPoint)plotSpace:(CPTPlotSpace *)space willDisplaceBy:(CGPoint)proposedDisplacementVector; + +/// @} + +/// @name Plot Range Changes +/// @{ + +/** @brief (Optional) Notifies that plot space is going to change a plot range. + * @param space The plot space. + * @param newRange The proposed new plot range. + * @param coordinate The coordinate of the range. + * @return The new plot range to be used. + **/ +-(CPTPlotRange *)plotSpace:(CPTPlotSpace *)space willChangePlotRangeTo:(CPTPlotRange *)newRange forCoordinate:(CPTCoordinate)coordinate; + +/** @brief (Optional) Notifies that plot space has changed a plot range. + * @param space The plot space. + * @param coordinate The coordinate of the range. + **/ +-(void)plotSpace:(CPTPlotSpace *)space didChangePlotRangeForCoordinate:(CPTCoordinate)coordinate; + +/// @} + +/// @name User Interaction +/// @{ + +/** @brief (Optional) Notifies that plot space intercepted a device down event. + * @param space The plot space. + * @param event The native event (e.g., UIEvent on iPhone) + * @param point The point in the host view. + * @return Whether the plot space should handle the event or not. + * In either case, the delegate may choose to take extra actions, or handle the scaling itself. + **/ +-(BOOL)plotSpace:(CPTPlotSpace *)space shouldHandlePointingDeviceDownEvent:(id)event atPoint:(CGPoint)point; + +/** @brief (Optional) Notifies that plot space intercepted a device dragged event. + * @param space The plot space. + * @param event The native event (e.g., UIEvent on iPhone) + * @param point The point in the host view. + * @return Whether the plot space should handle the event or not. + * In either case, the delegate may choose to take extra actions, or handle the scaling itself. + **/ +-(BOOL)plotSpace:(CPTPlotSpace *)space shouldHandlePointingDeviceDraggedEvent:(id)event atPoint:(CGPoint)point; + +/** @brief (Optional) Notifies that plot space intercepted a device cancelled event. + * @param space The plot space. + * @param event The native event (e.g., UIEvent on iPhone) + * @return Whether the plot space should handle the event or not. + * In either case, the delegate may choose to take extra actions, or handle the scaling itself. + **/ +-(BOOL)plotSpace:(CPTPlotSpace *)space shouldHandlePointingDeviceCancelledEvent:(id)event; + +/** @brief (Optional) Notifies that plot space intercepted a device up event. + * @param space The plot space. + * @param event The native event (e.g., UIEvent on iPhone) + * @param point The point in the host view. + * @return Whether the plot space should handle the event or not. + * In either case, the delegate may choose to take extra actions, or handle the scaling itself. + **/ +-(BOOL)plotSpace:(CPTPlotSpace *)space shouldHandlePointingDeviceUpEvent:(id)event atPoint:(CGPoint)point; + +/// @} + +@end + +#pragma mark - + +@interface CPTPlotSpace : NSObject { + @private + __cpt_weak CPTGraph *graph; + id identifier; + __cpt_weak id delegate; + BOOL allowsUserInteraction; +} + +@property (nonatomic, readwrite, copy) id identifier; +@property (nonatomic, readwrite, assign) BOOL allowsUserInteraction; +@property (nonatomic, readwrite, cpt_weak_property) __cpt_weak CPTGraph *graph; +@property (nonatomic, readwrite, cpt_weak_property) __cpt_weak id delegate; + +@end + +#pragma mark - + +/** @category CPTPlotSpace(AbstractMethods) + * @brief CPTPlotSpace abstract methods—must be overridden by subclasses + **/ +@interface CPTPlotSpace(AbstractMethods) + +/// @name Coordinate Space Conversions +/// @{ +-(CGPoint)plotAreaViewPointForPlotPoint:(NSDecimal *)plotPoint; +-(CGPoint)plotAreaViewPointForDoublePrecisionPlotPoint:(double *)plotPoint; +-(void)plotPoint:(NSDecimal *)plotPoint forPlotAreaViewPoint:(CGPoint)point; +-(void)doublePrecisionPlotPoint:(double *)plotPoint forPlotAreaViewPoint:(CGPoint)point; +/// @} + +/// @name Coordinate Range +/// @{ +-(void)setPlotRange:(CPTPlotRange *)newRange forCoordinate:(CPTCoordinate)coordinate; +-(CPTPlotRange *)plotRangeForCoordinate:(CPTCoordinate)coordinate; +/// @} + +/// @name Scale Types +/// @{ +-(void)setScaleType:(CPTScaleType)newType forCoordinate:(CPTCoordinate)coordinate; +-(CPTScaleType)scaleTypeForCoordinate:(CPTCoordinate)coordinate; +/// @} + +/// @name Adjusting Ranges +/// @{ +-(void)scaleToFitPlots:(NSArray *)plots; +-(void)scaleBy:(CGFloat)interactionScale aboutPoint:(CGPoint)interactionPoint; +/// @} + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTPlotSpaceAnnotation.h b/CorePlot.framework/Versions/A/Headers/CPTPlotSpaceAnnotation.h new file mode 100644 index 0000000..28a3c64 --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTPlotSpaceAnnotation.h @@ -0,0 +1,16 @@ +#import "CPTAnnotation.h" +#import + +@class CPTPlotSpace; + +@interface CPTPlotSpaceAnnotation : CPTAnnotation { + NSArray *anchorPlotPoint; + CPTPlotSpace *plotSpace; +} + +@property (nonatomic, readwrite, copy) NSArray *anchorPlotPoint; +@property (nonatomic, readonly, retain) CPTPlotSpace *plotSpace; + +-(id)initWithPlotSpace:(CPTPlotSpace *)space anchorPlotPoint:(NSArray *)plotPoint; + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTPlotSymbol.h b/CorePlot.framework/Versions/A/Headers/CPTPlotSymbol.h new file mode 100644 index 0000000..69cdf48 --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTPlotSymbol.h @@ -0,0 +1,74 @@ +#import +#import + +/// @file + +@class CPTLineStyle; +@class CPTFill; +@class CPTShadow; + +/** + * @brief Plot symbol types. + **/ +typedef enum _CPTPlotSymbolType { + CPTPlotSymbolTypeNone, ///< No symbol. + CPTPlotSymbolTypeRectangle, ///< Rectangle symbol. + CPTPlotSymbolTypeEllipse, ///< Elliptical symbol. + CPTPlotSymbolTypeDiamond, ///< Diamond symbol. + CPTPlotSymbolTypeTriangle, ///< Triangle symbol. + CPTPlotSymbolTypeStar, ///< 5-point star symbol. + CPTPlotSymbolTypePentagon, ///< Pentagon symbol. + CPTPlotSymbolTypeHexagon, ///< Hexagon symbol. + CPTPlotSymbolTypeCross, ///< X symbol. + CPTPlotSymbolTypePlus, ///< Plus symbol. + CPTPlotSymbolTypeDash, ///< Dash symbol. + CPTPlotSymbolTypeSnow, ///< Snowflake symbol. + CPTPlotSymbolTypeCustom ///< Custom symbol. +} +CPTPlotSymbolType; + +@interface CPTPlotSymbol : NSObject { + @private + CGSize size; + CPTPlotSymbolType symbolType; + CPTLineStyle *lineStyle; + CPTFill *fill; + CGPathRef cachedSymbolPath; + CGPathRef customSymbolPath; + BOOL usesEvenOddClipRule; + CGLayerRef cachedLayer; + CPTShadow *shadow; +} + +@property (nonatomic, readwrite, assign) CGSize size; +@property (nonatomic, readwrite, assign) CPTPlotSymbolType symbolType; +@property (nonatomic, readwrite, retain) CPTLineStyle *lineStyle; +@property (nonatomic, readwrite, retain) CPTFill *fill; +@property (nonatomic, readwrite, copy) CPTShadow *shadow; +@property (nonatomic, readwrite, assign) CGPathRef customSymbolPath; +@property (nonatomic, readwrite, assign) BOOL usesEvenOddClipRule; + +/// @name Factory Methods +/// @{ ++(CPTPlotSymbol *)plotSymbol; ++(CPTPlotSymbol *)crossPlotSymbol; ++(CPTPlotSymbol *)ellipsePlotSymbol; ++(CPTPlotSymbol *)rectanglePlotSymbol; ++(CPTPlotSymbol *)plusPlotSymbol; ++(CPTPlotSymbol *)starPlotSymbol; ++(CPTPlotSymbol *)diamondPlotSymbol; ++(CPTPlotSymbol *)trianglePlotSymbol; ++(CPTPlotSymbol *)pentagonPlotSymbol; ++(CPTPlotSymbol *)hexagonPlotSymbol; ++(CPTPlotSymbol *)dashPlotSymbol; ++(CPTPlotSymbol *)snowPlotSymbol; ++(CPTPlotSymbol *)customPlotSymbolWithPath:(CGPathRef)aPath; +/// @} + +/// @name Drawing +/// @{ +-(void)renderInContext:(CGContextRef)theContext atPoint:(CGPoint)center scale:(CGFloat)scale alignToPixels:(BOOL)alignToPixels; +-(void)renderAsVectorInContext:(CGContextRef)theContext atPoint:(CGPoint)center scale:(CGFloat)scale; +/// @} + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTRangePlot.h b/CorePlot.framework/Versions/A/Headers/CPTRangePlot.h new file mode 100644 index 0000000..78befa2 --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTRangePlot.h @@ -0,0 +1,50 @@ +#import "CPTDefinitions.h" +#import "CPTPlot.h" +#import + +@class CPTLineStyle; +@class CPTFill; + +/// @ingroup plotBindingsRangePlot +/// @{ +extern NSString *const CPTRangePlotBindingXValues; +extern NSString *const CPTRangePlotBindingYValues; +extern NSString *const CPTRangePlotBindingHighValues; +extern NSString *const CPTRangePlotBindingLowValues; +extern NSString *const CPTRangePlotBindingLeftValues; +extern NSString *const CPTRangePlotBindingRightValues; +/// @} + +/** + * @brief Enumeration of range plot data source field types + **/ +typedef enum _CPTRangePlotField { + CPTRangePlotFieldX, ///< X values. + CPTRangePlotFieldY, ///< Y values. + CPTRangePlotFieldHigh, ///< relative High values. + CPTRangePlotFieldLow, ///< relative Low values. + CPTRangePlotFieldLeft, ///< relative Left values. + CPTRangePlotFieldRight, ///< relative Right values. +} +CPTRangePlotField; + +@interface CPTRangePlot : CPTPlot { + CPTLineStyle *barLineStyle; + CGFloat barWidth; + CGFloat gapHeight; + CGFloat gapWidth; + CPTFill *areaFill; +} + +/// @name Bar Appearance +/// @{ +@property (nonatomic, readwrite, copy) CPTLineStyle *barLineStyle; +@property (nonatomic, readwrite) CGFloat barWidth, gapHeight, gapWidth; +/// @} + +/// @name Area Fill +/// @{ +@property (nonatomic, copy) CPTFill *areaFill; +/// @} + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTResponder.h b/CorePlot.framework/Versions/A/Headers/CPTResponder.h new file mode 100644 index 0000000..e5f390f --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTResponder.h @@ -0,0 +1,53 @@ +#import +#import + +/** + * @brief The basis of all event processing in Core Plot. + **/ +@protocol CPTResponder + +/// @name User Interaction +/// @{ + +/** + * @brief (Required) Informs the receiver that the user has + * @if MacOnly pressed the mouse button. @endif + * @if iOSOnly touched the screen. @endif + * @param event The OS event. + * @param interactionPoint The coordinates of the interaction. + * @return Whether the event was handled or not. + **/ +-(BOOL)pointingDeviceDownEvent:(id)event atPoint:(CGPoint)interactionPoint; + +/** + * @brief (Required) Informs the receiver that the user has + * @if MacOnly released the mouse button. @endif + * @if iOSOnly lifted their finger off the screen. @endif + * @param event The OS event. + * @param interactionPoint The coordinates of the interaction. + * @return Whether the event was handled or not. + **/ +-(BOOL)pointingDeviceUpEvent:(id)event atPoint:(CGPoint)interactionPoint; + +/** + * @brief (Required) Informs the receiver that the user has moved + * @if MacOnly the mouse with the button pressed. @endif + * @if iOSOnly their finger while touching the screen. @endif + * @param event The OS event. + * @param interactionPoint The coordinates of the interaction. + * @return Whether the event was handled or not. + **/ +-(BOOL)pointingDeviceDraggedEvent:(id)event atPoint:(CGPoint)interactionPoint; + +/** + * @brief (Required) Informs the receiver that tracking of + * @if MacOnly mouse moves @endif + * @if iOSOnly touches @endif + * has been cancelled for any reason. + * @param event The OS event. + * @return Whether the event was handled or not. + **/ +-(BOOL)pointingDeviceCancelledEvent:(id)event; +/// @} + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTScatterPlot.h b/CorePlot.framework/Versions/A/Headers/CPTScatterPlot.h new file mode 100644 index 0000000..f8b88b9 --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTScatterPlot.h @@ -0,0 +1,130 @@ +#import "CPTDefinitions.h" +#import "CPTPlot.h" +#import + +/// @file + +@class CPTLineStyle; +@class CPTMutableNumericData; +@class CPTNumericData; +@class CPTPlotSymbol; +@class CPTScatterPlot; +@class CPTFill; + +/// @ingroup plotBindingsScatterPlot +/// @{ +extern NSString *const CPTScatterPlotBindingXValues; +extern NSString *const CPTScatterPlotBindingYValues; +extern NSString *const CPTScatterPlotBindingPlotSymbols; +/// @} + +/** + * @brief Enumeration of scatter plot data source field types + **/ +typedef enum _CPTScatterPlotField { + CPTScatterPlotFieldX, ///< X values. + CPTScatterPlotFieldY ///< Y values. +} +CPTScatterPlotField; + +/** + * @brief Enumeration of scatter plot interpolation algorithms + **/ +typedef enum _CPTScatterPlotInterpolation { + CPTScatterPlotInterpolationLinear, ///< Linear interpolation. + CPTScatterPlotInterpolationStepped, ///< Steps beginnning at data point. + CPTScatterPlotInterpolationHistogram ///< Steps centered at data point. +} +CPTScatterPlotInterpolation; + +#pragma mark - + +/** + * @brief A scatter plot data source. + **/ +@protocol CPTScatterPlotDataSource + +@optional + +/// @name Plot Symbols +/// @{ + +/** @brief (Optional) Gets a range of plot symbols for the given scatter plot. + * @param plot The scatter plot. + * @param indexRange The range of the data indexes of interest. + * @return An array of plot symbols. + **/ +-(NSArray *)symbolsForScatterPlot:(CPTScatterPlot *)plot recordIndexRange:(NSRange)indexRange; + +/** @brief (Optional) Gets a single plot symbol for the given scatter plot. + * This method will not be called if + * @link CPTScatterPlotDataSource::symbolsForScatterPlot:recordIndexRange: -symbolsForScatterPlot:recordIndexRange: @endlink + * is also implemented in the datasource. + * @param plot The scatter plot. + * @param index The data index of interest. + * @return The plot symbol to show for the point with the given index. + **/ +-(CPTPlotSymbol *)symbolForScatterPlot:(CPTScatterPlot *)plot recordIndex:(NSUInteger)index; + +/// @} + +@end + +#pragma mark - + +/** + * @brief Scatter plot delegate. + **/ +@protocol CPTScatterPlotDelegate + +@optional + +/// @name Point Selection +/// @{ + +/** @brief (Optional) Informs delegate that a point was touched. + * @param plot The scatter plot. + * @param index Index of touched point + **/ +-(void)scatterPlot:(CPTScatterPlot *)plot plotSymbolWasSelectedAtRecordIndex:(NSUInteger)index; + +/// @} + +@end + +#pragma mark - + +@interface CPTScatterPlot : CPTPlot { + @private + CPTScatterPlotInterpolation interpolation; + CPTLineStyle *dataLineStyle; + CPTPlotSymbol *plotSymbol; + CPTFill *areaFill; + CPTFill *areaFill2; + NSDecimal areaBaseValue; + NSDecimal areaBaseValue2; + CGFloat plotSymbolMarginForHitDetection; + NSArray *plotSymbols; +} + +@property (nonatomic, readwrite, copy) CPTLineStyle *dataLineStyle; +@property (nonatomic, readwrite, copy) CPTPlotSymbol *plotSymbol; +@property (nonatomic, readwrite, copy) CPTFill *areaFill; +@property (nonatomic, readwrite, copy) CPTFill *areaFill2; +@property (nonatomic, readwrite) NSDecimal areaBaseValue; +@property (nonatomic, readwrite) NSDecimal areaBaseValue2; +@property (nonatomic, readwrite, assign) CPTScatterPlotInterpolation interpolation; +@property (nonatomic, readwrite, assign) CGFloat plotSymbolMarginForHitDetection; + +/// @name Visible Points +/// @{ +-(NSUInteger)indexOfVisiblePointClosestToPlotAreaPoint:(CGPoint)viewPoint; +-(CGPoint)plotAreaPointOfVisiblePointAtIndex:(NSUInteger)index; +/// @} + +/// @name Plot Symbols +/// @{ +-(CPTPlotSymbol *)plotSymbolForRecordIndex:(NSUInteger)index; +/// @} + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTShadow.h b/CorePlot.framework/Versions/A/Headers/CPTShadow.h new file mode 100644 index 0000000..76093f9 --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTShadow.h @@ -0,0 +1,27 @@ +#import +#import + +@class CPTColor; + +@interface CPTShadow : NSObject { + @private + CGSize shadowOffset; + CGFloat shadowBlurRadius; + CPTColor *shadowColor; +} + +@property (nonatomic, readonly, assign) CGSize shadowOffset; +@property (nonatomic, readonly, assign) CGFloat shadowBlurRadius; +@property (nonatomic, readonly, retain) CPTColor *shadowColor; + +/// @name Factory Methods +/// @{ ++(id)shadow; +/// @} + +/// @name Drawing +/// @{ +-(void)setShadowInContext:(CGContextRef)theContext; +/// @} + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTTextLayer.h b/CorePlot.framework/Versions/A/Headers/CPTTextLayer.h new file mode 100644 index 0000000..5676c97 --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTTextLayer.h @@ -0,0 +1,29 @@ +#import "CPTLayer.h" +#import "CPTTextStyle.h" + +/// @file + +extern const CGFloat kCPTTextLayerMarginWidth; ///< Margin width around the text. + +@interface CPTTextLayer : CPTLayer { + @private + NSString *text; + CPTTextStyle *textStyle; +} + +@property (readwrite, copy, nonatomic) NSString *text; +@property (readwrite, retain, nonatomic) CPTTextStyle *textStyle; + +/// @name Initialization +/// @{ +-(id)initWithText:(NSString *)newText; +-(id)initWithText:(NSString *)newText style:(CPTTextStyle *)newStyle; +/// @} + +/// @name Layout +/// @{ +-(CGSize)sizeThatFits; +-(void)sizeToFit; +/// @} + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTTextStyle.h b/CorePlot.framework/Versions/A/Headers/CPTTextStyle.h new file mode 100644 index 0000000..eb0b47e --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTTextStyle.h @@ -0,0 +1,53 @@ +#import +#import + +/// @file + +@class CPTColor; + +/** + * @brief Enumeration of paragraph alignments. + **/ +typedef enum _CPTTextAlignment { + CPTTextAlignmentLeft, ///< Left alignment + CPTTextAlignmentCenter, ///< Center alignment + CPTTextAlignmentRight ///< Right alignment +} +CPTTextAlignment; + +@interface CPTTextStyle : NSObject { + @protected + NSString *fontName; + CGFloat fontSize; + CPTColor *color; + CPTTextAlignment textAlignment; +} + +@property (readonly, copy, nonatomic) NSString *fontName; +@property (readonly, assign, nonatomic) CGFloat fontSize; +@property (readonly, copy, nonatomic) CPTColor *color; +@property (readonly, assign, nonatomic) CPTTextAlignment textAlignment; + +/// @name Factory Methods +/// @{ ++(id)textStyle; +/// @} + +@end + +/** @category NSString(CPTTextStyleExtensions) + * @brief NSString extensions for drawing styled text. + **/ +@interface NSString(CPTTextStyleExtensions) + +/// @name Measurement +/// @{ +-(CGSize)sizeWithTextStyle:(CPTTextStyle *)style; +/// @} + +/// @name Drawing +/// @{ +-(void)drawInRect:(CGRect)rect withTextStyle:(CPTTextStyle *)style inContext:(CGContextRef)context; +/// @} + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTTheme.h b/CorePlot.framework/Versions/A/Headers/CPTTheme.h new file mode 100644 index 0000000..619da67 --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTTheme.h @@ -0,0 +1,53 @@ +#import + +/// @ingroup themeNames +/// @{ +extern NSString *const kCPTDarkGradientTheme; +extern NSString *const kCPTPlainBlackTheme; +extern NSString *const kCPTPlainWhiteTheme; +extern NSString *const kCPTSlateTheme; +extern NSString *const kCPTStocksTheme; +/// @} + +@class CPTGraph; +@class CPTPlotAreaFrame; +@class CPTAxisSet; +@class CPTMutableTextStyle; + +@interface CPTTheme : NSObject { + @private + Class graphClass; +} + +@property (nonatomic, readwrite, retain) Class graphClass; + +/// @name Theme Management +/// @{ ++(void)registerTheme:(Class)themeClass; ++(NSArray *)themeClasses; ++(CPTTheme *)themeNamed:(NSString *)theme; ++(NSString *)name; +/// @} + +/// @name Theme Usage +/// @{ +-(void)applyThemeToGraph:(CPTGraph *)graph; +/// @} + +@end + +/** @category CPTTheme(AbstractMethods) + * @brief CPTTheme abstract methods—must be overridden by subclasses + **/ +@interface CPTTheme(AbstractMethods) + +/// @name Theme Usage +/// @{ +-(id)newGraph; + +-(void)applyThemeToBackground:(CPTGraph *)graph; +-(void)applyThemeToPlotArea:(CPTPlotAreaFrame *)plotAreaFrame; +-(void)applyThemeToAxisSet:(CPTAxisSet *)axisSet; +/// @} + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTTimeFormatter.h b/CorePlot.framework/Versions/A/Headers/CPTTimeFormatter.h new file mode 100644 index 0000000..8dacbb2 --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTTimeFormatter.h @@ -0,0 +1,19 @@ +#import + +/// @file + +@interface CPTTimeFormatter : NSNumberFormatter { + @private + NSDateFormatter *dateFormatter; + NSDate *referenceDate; +} + +@property (nonatomic, readwrite, retain) NSDateFormatter *dateFormatter; +@property (nonatomic, readwrite, copy) NSDate *referenceDate; + +/// @name Initialization +/// @{ +-(id)initWithDateFormatter:(NSDateFormatter *)aDateFormatter; +/// @} + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTTradingRangePlot.h b/CorePlot.framework/Versions/A/Headers/CPTTradingRangePlot.h new file mode 100644 index 0000000..085334c --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTTradingRangePlot.h @@ -0,0 +1,70 @@ +#import "CPTDefinitions.h" +#import "CPTPlot.h" +#import + +/// @file + +@class CPTLineStyle; +@class CPTMutableNumericData; +@class CPTNumericData; +@class CPTTradingRangePlot; +@class CPTFill; + +/// @ingroup plotBindingsTradingRangePlot +/// @{ +extern NSString *const CPTTradingRangePlotBindingXValues; +extern NSString *const CPTTradingRangePlotBindingOpenValues; +extern NSString *const CPTTradingRangePlotBindingHighValues; +extern NSString *const CPTTradingRangePlotBindingLowValues; +extern NSString *const CPTTradingRangePlotBindingCloseValues; +/// @} + +/** + * @brief Enumeration of Quote plot render style types. + **/ +typedef enum _CPTTradingRangePlotStyle { + CPTTradingRangePlotStyleOHLC, ///< Open-High-Low-Close (OHLC) plot. + CPTTradingRangePlotStyleCandleStick ///< Candlestick plot. +} +CPTTradingRangePlotStyle; + +/** + * @brief Enumeration of Quote plot data source field types. + **/ +typedef enum _CPTTradingRangePlotField { + CPTTradingRangePlotFieldX, ///< X values. + CPTTradingRangePlotFieldOpen, ///< Open values. + CPTTradingRangePlotFieldHigh, ///< High values. + CPTTradingRangePlotFieldLow, ///< Low values. + CPTTradingRangePlotFieldClose ///< Close values. +} +CPTTradingRangePlotField; + +#pragma mark - + +@interface CPTTradingRangePlot : CPTPlot { + @private + CPTLineStyle *lineStyle; + CPTLineStyle *increaseLineStyle; + CPTLineStyle *decreaseLineStyle; + CPTFill *increaseFill; + CPTFill *decreaseFill; + + CPTTradingRangePlotStyle plotStyle; + + CGFloat barWidth; + CGFloat stickLength; + CGFloat barCornerRadius; +} + +@property (nonatomic, readwrite, copy) CPTLineStyle *lineStyle; +@property (nonatomic, readwrite, copy) CPTLineStyle *increaseLineStyle; +@property (nonatomic, readwrite, copy) CPTLineStyle *decreaseLineStyle; +@property (nonatomic, readwrite, copy) CPTFill *increaseFill; +@property (nonatomic, readwrite, copy) CPTFill *decreaseFill; +@property (nonatomic, readwrite, assign) CPTTradingRangePlotStyle plotStyle; +@property (nonatomic, readwrite, assign) CGFloat barWidth; // In view coordinates +@property (nonatomic, readwrite, assign) CGFloat stickLength; // In view coordinates +@property (nonatomic, readwrite, assign) CGFloat barCornerRadius; + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTUtilities.h b/CorePlot.framework/Versions/A/Headers/CPTUtilities.h new file mode 100644 index 0000000..763ad8c --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTUtilities.h @@ -0,0 +1,121 @@ +#import "CPTDefinitions.h" +#import + +/// @file + +#if __cplusplus +extern "C" { +#endif + +/// @name Convert NSDecimal to Primitive Types +/// @{ +int8_t CPTDecimalCharValue(NSDecimal decimalNumber); +int16_t CPTDecimalShortValue(NSDecimal decimalNumber); +int32_t CPTDecimalLongValue(NSDecimal decimalNumber); +int64_t CPTDecimalLongLongValue(NSDecimal decimalNumber); +int CPTDecimalIntValue(NSDecimal decimalNumber); +NSInteger CPTDecimalIntegerValue(NSDecimal decimalNumber); + +uint8_t CPTDecimalUnsignedCharValue(NSDecimal decimalNumber); +uint16_t CPTDecimalUnsignedShortValue(NSDecimal decimalNumber); +uint32_t CPTDecimalUnsignedLongValue(NSDecimal decimalNumber); +uint64_t CPTDecimalUnsignedLongLongValue(NSDecimal decimalNumber); +unsigned int CPTDecimalUnsignedIntValue(NSDecimal decimalNumber); +NSUInteger CPTDecimalUnsignedIntegerValue(NSDecimal decimalNumber); + +float CPTDecimalFloatValue(NSDecimal decimalNumber); +double CPTDecimalDoubleValue(NSDecimal decimalNumber); +CGFloat CPTDecimalCGFloatValue(NSDecimal decimalNumber); + +NSString *CPTDecimalStringValue(NSDecimal decimalNumber); + +/// @} + +/// @name Convert Primitive Types to NSDecimal +/// @{ +NSDecimal CPTDecimalFromChar(int8_t i); +NSDecimal CPTDecimalFromShort(int16_t i); +NSDecimal CPTDecimalFromLong(int32_t i); +NSDecimal CPTDecimalFromLongLong(int64_t i); +NSDecimal CPTDecimalFromInt(int i); +NSDecimal CPTDecimalFromInteger(NSInteger i); + +NSDecimal CPTDecimalFromUnsignedChar(uint8_t i); +NSDecimal CPTDecimalFromUnsignedShort(uint16_t i); +NSDecimal CPTDecimalFromUnsignedLong(uint32_t i); +NSDecimal CPTDecimalFromUnsignedLongLong(uint64_t i); +NSDecimal CPTDecimalFromUnsignedInt(unsigned int i); +NSDecimal CPTDecimalFromUnsignedInteger(NSUInteger i); + +NSDecimal CPTDecimalFromFloat(float f); +NSDecimal CPTDecimalFromDouble(double d); +NSDecimal CPTDecimalFromCGFloat(CGFloat f); + +NSDecimal CPTDecimalFromString(NSString *stringRepresentation); + +/// @} + +/// @name NSDecimal Arithmetic +/// @{ +NSDecimal CPTDecimalAdd(NSDecimal leftOperand, NSDecimal rightOperand); +NSDecimal CPTDecimalSubtract(NSDecimal leftOperand, NSDecimal rightOperand); +NSDecimal CPTDecimalMultiply(NSDecimal leftOperand, NSDecimal rightOperand); +NSDecimal CPTDecimalDivide(NSDecimal numerator, NSDecimal denominator); + +/// @} + +/// @name NSDecimal Comparison +/// @{ +BOOL CPTDecimalGreaterThan(NSDecimal leftOperand, NSDecimal rightOperand); +BOOL CPTDecimalGreaterThanOrEqualTo(NSDecimal leftOperand, NSDecimal rightOperand); +BOOL CPTDecimalLessThan(NSDecimal leftOperand, NSDecimal rightOperand); +BOOL CPTDecimalLessThanOrEqualTo(NSDecimal leftOperand, NSDecimal rightOperand); +BOOL CPTDecimalEquals(NSDecimal leftOperand, NSDecimal rightOperand); + +/// @} + +/// @name NSDecimal Utilities +/// @{ +NSDecimal CPTDecimalNaN(void); + +/// @} + +/// @name Ranges +/// @{ +NSRange CPTExpandedRange(NSRange range, NSInteger expandBy); + +/// @} + +/// @name Coordinates +/// @{ +CPTCoordinate CPTOrthogonalCoordinate(CPTCoordinate coord); + +/// @} + +/// @name Gradient Colors +/// @{ +CPTRGBAColor CPTRGBAColorFromCGColor(CGColorRef color); + +/// @} + +/// @name Quartz Pixel-Alignment Functions +/// @{ +CGPoint CPTAlignPointToUserSpace(CGContextRef context, CGPoint p); +CGSize CPTAlignSizeToUserSpace(CGContextRef context, CGSize s); +CGRect CPTAlignRectToUserSpace(CGContextRef context, CGRect r); + +CGPoint CPTAlignIntegralPointToUserSpace(CGContextRef context, CGPoint p); + +/// @} + +/// @name String Formatting for Core Graphics Structs +/// @{ +NSString *CPTStringFromPoint(CGPoint p); +NSString *CPTStringFromSize(CGSize s); +NSString *CPTStringFromRect(CGRect r); + +/// @} + +#if __cplusplus +} +#endif diff --git a/CorePlot.framework/Versions/A/Headers/CPTXYAxis.h b/CorePlot.framework/Versions/A/Headers/CPTXYAxis.h new file mode 100644 index 0000000..0a7dbc1 --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTXYAxis.h @@ -0,0 +1,18 @@ +#import "CPTAxis.h" +#import + +@class CPTConstraints; + +@interface CPTXYAxis : CPTAxis { + @private + NSDecimal orthogonalCoordinateDecimal; + CPTConstraints *axisConstraints; +} + +/// @name Positioning +/// @{ +@property (nonatomic, readwrite) NSDecimal orthogonalCoordinateDecimal; +@property (nonatomic, readwrite, retain) CPTConstraints *axisConstraints; +/// @} + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTXYAxisSet.h b/CorePlot.framework/Versions/A/Headers/CPTXYAxisSet.h new file mode 100644 index 0000000..82c63d3 --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTXYAxisSet.h @@ -0,0 +1,12 @@ +#import "CPTAxisSet.h" +#import + +@class CPTXYAxis; + +@interface CPTXYAxisSet : CPTAxisSet { +} + +@property (nonatomic, readonly, retain) CPTXYAxis *xAxis; +@property (nonatomic, readonly, retain) CPTXYAxis *yAxis; + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTXYGraph.h b/CorePlot.framework/Versions/A/Headers/CPTXYGraph.h new file mode 100644 index 0000000..913b6ef --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTXYGraph.h @@ -0,0 +1,16 @@ +#import "CPTDefinitions.h" +#import "CPTGraph.h" +#import + +@interface CPTXYGraph : CPTGraph { + @private + CPTScaleType xScaleType; + CPTScaleType yScaleType; +} + +/// @name Initialization +/// @{ +-(id)initWithFrame:(CGRect)newFrame xScaleType:(CPTScaleType)newXScaleType yScaleType:(CPTScaleType)newYScaleType; +/// @} + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CPTXYPlotSpace.h b/CorePlot.framework/Versions/A/Headers/CPTXYPlotSpace.h new file mode 100644 index 0000000..7780f21 --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CPTXYPlotSpace.h @@ -0,0 +1,25 @@ +#import "CPTDefinitions.h" +#import "CPTPlotSpace.h" + +@class CPTPlotRange; + +@interface CPTXYPlotSpace : CPTPlotSpace { + @private + CPTPlotRange *xRange; + CPTPlotRange *yRange; + CPTPlotRange *globalXRange; + CPTPlotRange *globalYRange; + CPTScaleType xScaleType; + CPTScaleType yScaleType; + CGPoint lastDragPoint; + BOOL isDragging; +} + +@property (nonatomic, readwrite, copy) CPTPlotRange *xRange; +@property (nonatomic, readwrite, copy) CPTPlotRange *yRange; +@property (nonatomic, readwrite, copy) CPTPlotRange *globalXRange; +@property (nonatomic, readwrite, copy) CPTPlotRange *globalYRange; +@property (nonatomic, readwrite, assign) CPTScaleType xScaleType; +@property (nonatomic, readwrite, assign) CPTScaleType yScaleType; + +@end diff --git a/CorePlot.framework/Versions/A/Headers/CorePlot.h b/CorePlot.framework/Versions/A/Headers/CorePlot.h new file mode 100644 index 0000000..5620a4a --- /dev/null +++ b/CorePlot.framework/Versions/A/Headers/CorePlot.h @@ -0,0 +1,61 @@ +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import diff --git a/CorePlot.framework/Versions/A/PrivateHeaders/CPTAxisLabelGroup.h b/CorePlot.framework/Versions/A/PrivateHeaders/CPTAxisLabelGroup.h new file mode 100644 index 0000000..eb19f37 --- /dev/null +++ b/CorePlot.framework/Versions/A/PrivateHeaders/CPTAxisLabelGroup.h @@ -0,0 +1,7 @@ +#import "CPTLayer.h" +#import + +@interface CPTAxisLabelGroup : CPTLayer { +} + +@end diff --git a/CorePlot.framework/Versions/A/PrivateHeaders/CPTGridLineGroup.h b/CorePlot.framework/Versions/A/PrivateHeaders/CPTGridLineGroup.h new file mode 100644 index 0000000..2803687 --- /dev/null +++ b/CorePlot.framework/Versions/A/PrivateHeaders/CPTGridLineGroup.h @@ -0,0 +1,14 @@ +#import "CPTLayer.h" + +@class CPTPlotArea; + +@interface CPTGridLineGroup : CPTLayer { + @private + __cpt_weak CPTPlotArea *plotArea; + BOOL major; +} + +@property (nonatomic, readwrite, assign) __cpt_weak CPTPlotArea *plotArea; +@property (nonatomic, readwrite) BOOL major; + +@end diff --git a/CorePlot.framework/Versions/A/PrivateHeaders/CPTGridLines.h b/CorePlot.framework/Versions/A/PrivateHeaders/CPTGridLines.h new file mode 100644 index 0000000..2519491 --- /dev/null +++ b/CorePlot.framework/Versions/A/PrivateHeaders/CPTGridLines.h @@ -0,0 +1,15 @@ +#import "CPTLayer.h" +#import + +@class CPTAxis; + +@interface CPTGridLines : CPTLayer { + @private + __cpt_weak CPTAxis *axis; + BOOL major; +} + +@property (nonatomic, readwrite, assign) __cpt_weak CPTAxis *axis; +@property (nonatomic, readwrite) BOOL major; + +@end diff --git a/CorePlot.framework/Versions/A/PrivateHeaders/CPTPlotGroup.h b/CorePlot.framework/Versions/A/PrivateHeaders/CPTPlotGroup.h new file mode 100644 index 0000000..5d75489 --- /dev/null +++ b/CorePlot.framework/Versions/A/PrivateHeaders/CPTPlotGroup.h @@ -0,0 +1,14 @@ +#import "CPTLayer.h" + +@class CPTPlot; + +@interface CPTPlotGroup : CPTLayer { +} + +/// @name Adding and Removing Plots +/// @{ +-(void)addPlot:(CPTPlot *)plot; +-(void)removePlot:(CPTPlot *)plot; +/// @} + +@end diff --git a/CorePlot.framework/Versions/A/PrivateHeaders/NSCoderExtensions.h b/CorePlot.framework/Versions/A/PrivateHeaders/NSCoderExtensions.h new file mode 100644 index 0000000..c73cff1 --- /dev/null +++ b/CorePlot.framework/Versions/A/PrivateHeaders/NSCoderExtensions.h @@ -0,0 +1,37 @@ +#import +#import + +/** @category NSCoder(CPTExtensions) + * @brief Core Plot extensions to NSCoder. + **/ +@interface NSCoder(CPTExtensions) + +/// @name Encoding Data +/// @{ +-(void)encodeCGFloat:(CGFloat)number forKey:(NSString *)key; +-(void)encodeCPTPoint:(CGPoint)point forKey:(NSString *)key; +-(void)encodeCPTSize:(CGSize)size forKey:(NSString *)key; +-(void)encodeCPTRect:(CGRect)rect forKey:(NSString *)key; + +-(void)encodeCGColorSpace:(CGColorSpaceRef)colorSpace forKey:(NSString *)key; +-(void)encodeCGPath:(CGPathRef)path forKey:(NSString *)key; +-(void)encodeCGImage:(CGImageRef)image forKey:(NSString *)key; + +-(void)encodeDecimal:(NSDecimal)number forKey:(NSString *)key; +/// @} + +/// @name Decoding Data +/// @{ +-(CGFloat)decodeCGFloatForKey:(NSString *)key; +-(CGPoint)decodeCPTPointForKey:(NSString *)key; +-(CGSize)decodeCPTSizeForKey:(NSString *)key; +-(CGRect)decodeCPTRectForKey:(NSString *)key; + +-(CGColorSpaceRef)newCGColorSpaceDecodeForKey:(NSString *)key; +-(CGPathRef)newCGPathDecodeForKey:(NSString *)key; +-(CGImageRef)newCGImageDecodeForKey:(NSString *)key; + +-(NSDecimal)decodeDecimalForKey:(NSString *)key; +/// @} + +@end diff --git a/CorePlot.framework/Versions/A/PrivateHeaders/NSDecimalNumberExtensions.h b/CorePlot.framework/Versions/A/PrivateHeaders/NSDecimalNumberExtensions.h new file mode 100644 index 0000000..0ee0687 --- /dev/null +++ b/CorePlot.framework/Versions/A/PrivateHeaders/NSDecimalNumberExtensions.h @@ -0,0 +1,9 @@ +#import +#import + +/** @category NSDecimalNumber(CPTExtensions) + * @brief Core Plot extensions to NSDecimalNumber. + **/ +@interface NSDecimalNumber(CPTExtensions) + +@end diff --git a/CorePlot.framework/Versions/A/PrivateHeaders/NSNumberExtensions.h b/CorePlot.framework/Versions/A/PrivateHeaders/NSNumberExtensions.h new file mode 100644 index 0000000..fdefdfb --- /dev/null +++ b/CorePlot.framework/Versions/A/PrivateHeaders/NSNumberExtensions.h @@ -0,0 +1,16 @@ +#import +#import + +/** @category NSNumber(CPTExtensions) + * @brief Core Plot extensions to NSNumber. + **/ +@interface NSNumber(CPTExtensions) + ++(NSNumber *)numberWithCGFloat:(CGFloat)number; + +-(CGFloat)cgFloatValue; +-(id)initWithCGFloat:(CGFloat)number; + +-(NSDecimalNumber *)decimalNumber; + +@end diff --git a/CorePlot.framework/Versions/A/PrivateHeaders/_CPTConstraintsFixed.h b/CorePlot.framework/Versions/A/PrivateHeaders/_CPTConstraintsFixed.h new file mode 100644 index 0000000..ddb4eb7 --- /dev/null +++ b/CorePlot.framework/Versions/A/PrivateHeaders/_CPTConstraintsFixed.h @@ -0,0 +1,26 @@ +#import "CPTConstraints.h" +#import + +@interface _CPTConstraintsFixed : CPTConstraints { + @private + CGFloat offset; + BOOL isFixedToLower; +} + +/// @name Initialization +/// @{ +-(id)initWithLowerOffset:(CGFloat)newOffset; +-(id)initWithUpperOffset:(CGFloat)newOffset; +/// @} + +/// @name Comparison +/// @{ +-(BOOL)isEqualToConstraint:(CPTConstraints *)otherConstraint; +/// @} + +/// @name Position +/// @{ +-(CGFloat)positionForLowerBound:(CGFloat)lowerBound upperBound:(CGFloat)upperBound; +/// @} + +@end diff --git a/CorePlot.framework/Versions/A/PrivateHeaders/_CPTConstraintsRelative.h b/CorePlot.framework/Versions/A/PrivateHeaders/_CPTConstraintsRelative.h new file mode 100644 index 0000000..8191a05 --- /dev/null +++ b/CorePlot.framework/Versions/A/PrivateHeaders/_CPTConstraintsRelative.h @@ -0,0 +1,24 @@ +#import "CPTConstraints.h" +#import + +@interface _CPTConstraintsRelative : CPTConstraints { + @private + CGFloat offset; +} + +/// @name Initialization +/// @{ +-(id)initWithRelativeOffset:(CGFloat)newOffset; +/// @} + +/// @name Comparison +/// @{ +-(BOOL)isEqualToConstraint:(CPTConstraints *)otherConstraint; +/// @} + +/// @name Position +/// @{ +-(CGFloat)positionForLowerBound:(CGFloat)lowerBound upperBound:(CGFloat)upperBound; +/// @} + +@end diff --git a/CorePlot.framework/Versions/A/PrivateHeaders/_CPTDarkGradientTheme.h b/CorePlot.framework/Versions/A/PrivateHeaders/_CPTDarkGradientTheme.h new file mode 100644 index 0000000..7d6e784 --- /dev/null +++ b/CorePlot.framework/Versions/A/PrivateHeaders/_CPTDarkGradientTheme.h @@ -0,0 +1,6 @@ +#import "_CPTXYTheme.h" + +@interface _CPTDarkGradientTheme : _CPTXYTheme { +} + +@end diff --git a/CorePlot.framework/Versions/A/PrivateHeaders/_CPTFillColor.h b/CorePlot.framework/Versions/A/PrivateHeaders/_CPTFillColor.h new file mode 100644 index 0000000..b9264df --- /dev/null +++ b/CorePlot.framework/Versions/A/PrivateHeaders/_CPTFillColor.h @@ -0,0 +1,20 @@ +#import "CPTFill.h" +#import + +@interface _CPTFillColor : CPTFill { + @private + CPTColor *fillColor; +} + +/// @name Initialization +/// @{ +-(id)initWithColor:(CPTColor *)aCcolor; +/// @} + +/// @name Drawing +/// @{ +-(void)fillRect:(CGRect)theRect inContext:(CGContextRef)theContext; +-(void)fillPathInContext:(CGContextRef)theContext; +/// @} + +@end diff --git a/CorePlot.framework/Versions/A/PrivateHeaders/_CPTFillGradient.h b/CorePlot.framework/Versions/A/PrivateHeaders/_CPTFillGradient.h new file mode 100644 index 0000000..31f7263 --- /dev/null +++ b/CorePlot.framework/Versions/A/PrivateHeaders/_CPTFillGradient.h @@ -0,0 +1,22 @@ +#import "CPTFill.h" +#import + +@class CPTGradient; + +@interface _CPTFillGradient : CPTFill { + @private + CPTGradient *fillGradient; +} + +/// @name Initialization +/// @{ +-(id)initWithGradient:(CPTGradient *)aGradient; +/// @} + +/// @name Drawing +/// @{ +-(void)fillRect:(CGRect)theRect inContext:(CGContextRef)theContext; +-(void)fillPathInContext:(CGContextRef)theContext; +/// @} + +@end diff --git a/CorePlot.framework/Versions/A/PrivateHeaders/_CPTFillImage.h b/CorePlot.framework/Versions/A/PrivateHeaders/_CPTFillImage.h new file mode 100644 index 0000000..5f1ca59 --- /dev/null +++ b/CorePlot.framework/Versions/A/PrivateHeaders/_CPTFillImage.h @@ -0,0 +1,22 @@ +#import "CPTFill.h" +#import + +@class CPTImage; + +@interface _CPTFillImage : CPTFill { + @private + CPTImage *fillImage; +} + +/// @name Initialization +/// @{ +-(id)initWithImage:(CPTImage *)anImage; +/// @} + +/// @name Drawing +/// @{ +-(void)fillRect:(CGRect)theRect inContext:(CGContextRef)theContext; +-(void)fillPathInContext:(CGContextRef)theContext; +/// @} + +@end diff --git a/CorePlot.framework/Versions/A/PrivateHeaders/_CPTPlainBlackTheme.h b/CorePlot.framework/Versions/A/PrivateHeaders/_CPTPlainBlackTheme.h new file mode 100644 index 0000000..46d25c3 --- /dev/null +++ b/CorePlot.framework/Versions/A/PrivateHeaders/_CPTPlainBlackTheme.h @@ -0,0 +1,6 @@ +#import "_CPTXYTheme.h" + +@interface _CPTPlainBlackTheme : _CPTXYTheme { +} + +@end diff --git a/CorePlot.framework/Versions/A/PrivateHeaders/_CPTPlainWhiteTheme.h b/CorePlot.framework/Versions/A/PrivateHeaders/_CPTPlainWhiteTheme.h new file mode 100644 index 0000000..5375648 --- /dev/null +++ b/CorePlot.framework/Versions/A/PrivateHeaders/_CPTPlainWhiteTheme.h @@ -0,0 +1,6 @@ +#import "_CPTXYTheme.h" + +@interface _CPTPlainWhiteTheme : _CPTXYTheme { +} + +@end diff --git a/CorePlot.framework/Versions/A/PrivateHeaders/_CPTSlateTheme.h b/CorePlot.framework/Versions/A/PrivateHeaders/_CPTSlateTheme.h new file mode 100644 index 0000000..ea3acba --- /dev/null +++ b/CorePlot.framework/Versions/A/PrivateHeaders/_CPTSlateTheme.h @@ -0,0 +1,6 @@ +#import "_CPTXYTheme.h" + +@interface _CPTSlateTheme : _CPTXYTheme { +} + +@end diff --git a/CorePlot.framework/Versions/A/PrivateHeaders/_CPTStocksTheme.h b/CorePlot.framework/Versions/A/PrivateHeaders/_CPTStocksTheme.h new file mode 100644 index 0000000..298917b --- /dev/null +++ b/CorePlot.framework/Versions/A/PrivateHeaders/_CPTStocksTheme.h @@ -0,0 +1,6 @@ +#import "_CPTXYTheme.h" + +@interface _CPTStocksTheme : _CPTXYTheme { +} + +@end diff --git a/CorePlot.framework/Versions/A/PrivateHeaders/_CPTXYTheme.h b/CorePlot.framework/Versions/A/PrivateHeaders/_CPTXYTheme.h new file mode 100644 index 0000000..0ba57a9 --- /dev/null +++ b/CorePlot.framework/Versions/A/PrivateHeaders/_CPTXYTheme.h @@ -0,0 +1,6 @@ +#import "CPTTheme.h" + +@interface _CPTXYTheme : CPTTheme { +} + +@end diff --git a/CorePlot.framework/Versions/A/Resources/English.lproj/InfoPlist.strings b/CorePlot.framework/Versions/A/Resources/English.lproj/InfoPlist.strings new file mode 100644 index 0000000..5e45963 Binary files /dev/null and b/CorePlot.framework/Versions/A/Resources/English.lproj/InfoPlist.strings differ diff --git a/CorePlot.framework/Versions/A/Resources/Info.plist b/CorePlot.framework/Versions/A/Resources/Info.plist new file mode 100644 index 0000000..fe85499 --- /dev/null +++ b/CorePlot.framework/Versions/A/Resources/Info.plist @@ -0,0 +1,38 @@ + + + + + BuildMachineOSBuild + 11D50 + CFBundleDevelopmentRegion + English + CFBundleExecutable + CorePlot + CFBundleIdentifier + org.coreplot.CorePlot + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + CorePlot + CFBundlePackageType + FMWK + CFBundleSignature + ???? + CFBundleVersion + 1.0 + DTCompiler + + DTPlatformBuild + 4D199 + DTPlatformVersion + GM + DTSDKBuild + 11C63 + DTSDKName + macosx10.7 + DTXcode + 0420 + DTXcodeBuild + 4D199 + + diff --git a/CorePlot.framework/Versions/A/Resources/License.txt b/CorePlot.framework/Versions/A/Resources/License.txt new file mode 100644 index 0000000..d2a98e2 --- /dev/null +++ b/CorePlot.framework/Versions/A/Resources/License.txt @@ -0,0 +1,9 @@ +Copyright (c) 2012, Drew McCormack, Brad Larson, Eric Skroch, Barry Wark, Dirkjan Krijnders, Rick Maddy, Vijay Kalusani, Caleb Cannon, Jeff Buck, Thomas Elstner, Jeroen Leenarts, Craig Hockenberry, Hartwig Wiesmann, Koen van der Drift. +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 the Core Plot Project nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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. diff --git a/CorePlot.framework/Versions/Current b/CorePlot.framework/Versions/Current new file mode 120000 index 0000000..8c7e5a6 --- /dev/null +++ b/CorePlot.framework/Versions/Current @@ -0,0 +1 @@ +A \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..7f158f8 --- /dev/null +++ b/LICENSE @@ -0,0 +1,30 @@ + +// Copyright (c) 2012 Stephen Oliver +// + +/* + + 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 the nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 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. + + + */ diff --git a/README b/README deleted file mode 100644 index d6a4ac3..0000000 --- a/README +++ /dev/null @@ -1,16 +0,0 @@ -BitTicker is Copyright 2011 Stephen Oliver -http://github.com/mrsteveman1 - -This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA diff --git a/README.markdown b/README.markdown new file mode 100755 index 0000000..5a65ab9 --- /dev/null +++ b/README.markdown @@ -0,0 +1,5 @@ +### BitTicker + +BitTicker is a Bitcoin stock ticker built to work with MtGox Bitcoin market. + +The binary version available from the download button should work fine, but the source code is in a state of transition so don't plan on it being usable yet.