/Source/externals/GData/Source/HTTPFetcher/GTMGatherInputStream.m

http://google-email-uploader-mac.googlecode.com/ · Objective C · 197 lines · 121 code · 46 blank · 30 comment · 12 complexity · cbaad9311b824ba582771db71829ecf5 MD5 · raw file

  1. /* Copyright (c) 2010 Google Inc.
  2. *
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. #import "GTMGatherInputStream.h"
  16. @implementation GTMGatherInputStream
  17. + (NSInputStream *)streamWithArray:(NSArray *)dataArray {
  18. return [[[self alloc] initWithArray:dataArray] autorelease];
  19. }
  20. - (id)initWithArray:(NSArray *)dataArray {
  21. self = [super init];
  22. if (self) {
  23. dataArray_ = [dataArray retain];
  24. arrayIndex_ = 0;
  25. dataOffset_ = 0;
  26. [self setDelegate:self]; // An NSStream's default delegate should be self.
  27. // We use a dummy input stream to handle all the various undocumented
  28. // messages the system sends to an input stream.
  29. //
  30. // Contrary to documentation, inputStreamWithData neither copies nor
  31. // retains the data in Mac OS X 10.4, so we must retain it.
  32. // (Radar 5167591)
  33. dummyData_ = [[NSData alloc] initWithBytes:"x" length:1];
  34. dummyStream_ = [[NSInputStream alloc] initWithData:dummyData_];
  35. }
  36. return self;
  37. }
  38. - (void)dealloc {
  39. [dataArray_ release];
  40. [dummyStream_ release];
  41. [dummyData_ release];
  42. [super dealloc];
  43. }
  44. - (NSInteger)read:(uint8_t *)buffer maxLength:(NSUInteger)len {
  45. NSInteger bytesRead = 0;
  46. NSUInteger bytesRemaining = len;
  47. // read bytes from the currently-indexed array
  48. while ((bytesRemaining > 0) && (arrayIndex_ < [dataArray_ count])) {
  49. NSData* data = [dataArray_ objectAtIndex:arrayIndex_];
  50. NSUInteger dataLen = [data length];
  51. NSUInteger dataBytesLeft = dataLen - (NSUInteger)dataOffset_;
  52. NSUInteger bytesToCopy = MIN(bytesRemaining, dataBytesLeft);
  53. NSRange range = NSMakeRange((NSUInteger) dataOffset_, bytesToCopy);
  54. [data getBytes:(buffer + bytesRead) range:range];
  55. bytesRead += bytesToCopy;
  56. dataOffset_ += bytesToCopy;
  57. bytesRemaining -= bytesToCopy;
  58. if (dataOffset_ == (long long)dataLen) {
  59. dataOffset_ = 0;
  60. arrayIndex_++;
  61. }
  62. }
  63. if (bytesRead == 0) {
  64. // We are at the end our our stream, so we read all of the data on our
  65. // dummy input stream to make sure it is in the "fully read" state.
  66. uint8_t leftOverBytes[2];
  67. (void) [dummyStream_ read:leftOverBytes maxLength:sizeof(leftOverBytes)];
  68. }
  69. return bytesRead;
  70. }
  71. - (BOOL)getBuffer:(uint8_t **)buffer length:(NSUInteger *)len {
  72. return NO; // We don't support this style of reading.
  73. }
  74. - (BOOL)hasBytesAvailable {
  75. // if we return no, the read never finishes, even if we've already
  76. // delivered all the bytes
  77. return YES;
  78. }
  79. #pragma mark -
  80. // Pass other expected messages on to the dummy input stream
  81. - (void)open {
  82. [dummyStream_ open];
  83. }
  84. - (void)close {
  85. [dummyStream_ close];
  86. // 10.4's NSURLConnection tends to retain streams needlessly,
  87. // so we'll free up the data array right away
  88. [dataArray_ release];
  89. dataArray_ = nil;
  90. }
  91. - (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent {
  92. if (delegate_ != self) {
  93. [delegate_ stream:self handleEvent:streamEvent];
  94. }
  95. }
  96. - (id)delegate {
  97. return delegate_;
  98. }
  99. - (void)setDelegate:(id)delegate {
  100. if (delegate == nil) {
  101. delegate_ = self;
  102. [dummyStream_ setDelegate:nil];
  103. } else {
  104. delegate_ = delegate;
  105. [dummyStream_ setDelegate:self];
  106. }
  107. }
  108. - (id)propertyForKey:(NSString *)key {
  109. return [dummyStream_ propertyForKey:key];
  110. }
  111. - (BOOL)setProperty:(id)property forKey:(NSString *)key {
  112. return [dummyStream_ setProperty:property forKey:key];
  113. }
  114. - (void)scheduleInRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode {
  115. [dummyStream_ scheduleInRunLoop:aRunLoop forMode:mode];
  116. }
  117. - (void)removeFromRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode {
  118. [dummyStream_ removeFromRunLoop:aRunLoop forMode:mode];
  119. }
  120. - (NSStreamStatus)streamStatus {
  121. return [dummyStream_ streamStatus];
  122. }
  123. - (NSError *)streamError {
  124. return [dummyStream_ streamError];
  125. }
  126. #pragma mark -
  127. // We'll forward all unexpected messages to our dummy stream
  128. + (NSMethodSignature*)methodSignatureForSelector:(SEL)selector {
  129. return [NSInputStream methodSignatureForSelector:selector];
  130. }
  131. + (void)forwardInvocation:(NSInvocation*)invocation {
  132. [invocation invokeWithTarget:[NSInputStream class]];
  133. }
  134. - (BOOL)respondsToSelector:(SEL)selector {
  135. return [dummyStream_ respondsToSelector:selector];
  136. }
  137. - (NSMethodSignature*)methodSignatureForSelector:(SEL)selector {
  138. return [dummyStream_ methodSignatureForSelector:selector];
  139. }
  140. - (void)forwardInvocation:(NSInvocation*)invocation {
  141. #if 0
  142. // uncomment this section to see the messages the NSInputStream receives
  143. SEL selector;
  144. NSString *selName;
  145. selector=[invocation selector];
  146. selName=NSStringFromSelector(selector);
  147. NSLog(@"-forwardInvocation: %@",selName);
  148. #endif
  149. [invocation invokeWithTarget:dummyStream_];
  150. }
  151. @end