Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Initial implementation of HSCountingInputStream

  • Loading branch information...
commit 3403a602bfc62b08bf1069ce2982f4de2719e1a0 1 parent 0f997ed
@bjhomer authored
View
10 HSCountingInputStream.xcodeproj/project.pbxproj
@@ -9,6 +9,7 @@
/* Begin PBXBuildFile section */
B7B206F713557E9500C1C6BA /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B7B206F613557E9500C1C6BA /* Foundation.framework */; };
B7B206FA13557E9500C1C6BA /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = B7B206F913557E9500C1C6BA /* main.m */; };
+ B7B2070513557ED300C1C6BA /* HSCountingInputStream.m in Sources */ = {isa = PBXBuildFile; fileRef = B7B2070413557ED300C1C6BA /* HSCountingInputStream.m */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
@@ -27,8 +28,9 @@
B7B206F213557E9500C1C6BA /* HSCountingInputStream */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = HSCountingInputStream; sourceTree = BUILT_PRODUCTS_DIR; };
B7B206F613557E9500C1C6BA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
B7B206F913557E9500C1C6BA /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
- B7B206FC13557E9500C1C6BA /* HSCountingInputStream-Prefix.pch */ = {isa = PBXFileReference; path = "HSCountingInputStream-Prefix.pch"; sourceTree = "<group>"; };
- B7B206FD13557E9500C1C6BA /* HSCountingInputStream.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = HSCountingInputStream.1; sourceTree = "<group>"; };
+ B7B206FC13557E9500C1C6BA /* HSCountingInputStream-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "HSCountingInputStream-Prefix.pch"; sourceTree = "<group>"; };
+ B7B2070313557ED300C1C6BA /* HSCountingInputStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HSCountingInputStream.h; sourceTree = "<group>"; };
+ B7B2070413557ED300C1C6BA /* HSCountingInputStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HSCountingInputStream.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -72,7 +74,8 @@
isa = PBXGroup;
children = (
B7B206F913557E9500C1C6BA /* main.m */,
- B7B206FD13557E9500C1C6BA /* HSCountingInputStream.1 */,
+ B7B2070313557ED300C1C6BA /* HSCountingInputStream.h */,
+ B7B2070413557ED300C1C6BA /* HSCountingInputStream.m */,
B7B206FB13557E9500C1C6BA /* Supporting Files */,
);
path = HSCountingInputStream;
@@ -137,6 +140,7 @@
buildActionMask = 2147483647;
files = (
B7B206FA13557E9500C1C6BA /* main.m in Sources */,
+ B7B2070513557ED300C1C6BA /* HSCountingInputStream.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
View
79 HSCountingInputStream/HSCountingInputStream.1
@@ -1,79 +0,0 @@
-.\"Modified from man(1) of FreeBSD, the NetBSD mdoc.template, and mdoc.samples.
-.\"See Also:
-.\"man mdoc.samples for a complete listing of options
-.\"man mdoc for the short list of editing options
-.\"/usr/share/misc/mdoc.template
-.Dd 4/13/11 \" DATE
-.Dt HSCountingInputStream 1 \" Program name and manual section number
-.Os Darwin
-.Sh NAME \" Section Header - required - don't modify
-.Nm HSCountingInputStream,
-.\" The following lines are read in generating the apropos(man -k) database. Use only key
-.\" words here as the database is built based on the words here and in the .ND line.
-.Nm Other_name_for_same_program(),
-.Nm Yet another name for the same program.
-.\" Use .Nm macro to designate other names for the documented program.
-.Nd This line parsed for whatis database.
-.Sh SYNOPSIS \" Section Header - required - don't modify
-.Nm
-.Op Fl abcd \" [-abcd]
-.Op Fl a Ar path \" [-a path]
-.Op Ar file \" [file]
-.Op Ar \" [file ...]
-.Ar arg0 \" Underlined argument - use .Ar anywhere to underline
-arg2 ... \" Arguments
-.Sh DESCRIPTION \" Section Header - required - don't modify
-Use the .Nm macro to refer to your program throughout the man page like such:
-.Nm
-Underlining is accomplished with the .Ar macro like this:
-.Ar underlined text .
-.Pp \" Inserts a space
-A list of items with descriptions:
-.Bl -tag -width -indent \" Begins a tagged list
-.It item a \" Each item preceded by .It macro
-Description of item a
-.It item b
-Description of item b
-.El \" Ends the list
-.Pp
-A list of flags and their descriptions:
-.Bl -tag -width -indent \" Differs from above in tag removed
-.It Fl a \"-a flag as a list item
-Description of -a flag
-.It Fl b
-Description of -b flag
-.El \" Ends the list
-.Pp
-.\" .Sh ENVIRONMENT \" May not be needed
-.\" .Bl -tag -width "ENV_VAR_1" -indent \" ENV_VAR_1 is width of the string ENV_VAR_1
-.\" .It Ev ENV_VAR_1
-.\" Description of ENV_VAR_1
-.\" .It Ev ENV_VAR_2
-.\" Description of ENV_VAR_2
-.\" .El
-.Sh FILES \" File used or created by the topic of the man page
-.Bl -tag -width "/Users/joeuser/Library/really_long_file_name" -compact
-.It Pa /usr/share/file_name
-FILE_1 description
-.It Pa /Users/joeuser/Library/really_long_file_name
-FILE_2 description
-.El \" Ends the list
-.\" .Sh DIAGNOSTICS \" May not be needed
-.\" .Bl -diag
-.\" .It Diagnostic Tag
-.\" Diagnostic informtion here.
-.\" .It Diagnostic Tag
-.\" Diagnostic informtion here.
-.\" .El
-.Sh SEE ALSO
-.\" List links in ascending order by section, alphabetically within a section.
-.\" Please do not reference files that do not exist without filing a bug report
-.Xr a 1 ,
-.Xr b 1 ,
-.Xr c 1 ,
-.Xr a 2 ,
-.Xr b 2 ,
-.Xr a 3 ,
-.Xr b 3
-.\" .Sh BUGS \" Document known, unremedied bugs
-.\" .Sh HISTORY \" Document history if command behaves in a unique manner
View
19 HSCountingInputStream/HSCountingInputStream.h
@@ -0,0 +1,19 @@
+//
+// HSCountingInputStream.h
+// HSCountingInputStream
+//
+// Created by BJ Homer on 4/13/11.
+// Copyright 2011 BJ Homer. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+
+@interface HSCountingInputStream : NSInputStream <NSStreamDelegate>
+
+@property (assign) char characterToCount;
+@property (readonly, assign) NSUInteger countedCharacters;
+
+- (id)initWithInputStream:(NSInputStream *)stream;
+
+@end
View
200 HSCountingInputStream/HSCountingInputStream.m
@@ -0,0 +1,200 @@
+//
+// HSCountingInputStream.m
+// HSCountingInputStream
+//
+// Created by BJ Homer on 4/13/11.
+// Copyright 2011 BJ Homer. All rights reserved.
+//
+
+#import "HSCountingInputStream.h"
+
+
+@implementation HSCountingInputStream
+{
+ NSInputStream *parentStream;
+ id <NSStreamDelegate> delegate;
+ NSUInteger characterCounter;
+
+ CFReadStreamClientCallBack copiedCallback;
+ CFStreamClientContext copiedContext;
+ CFOptionFlags requestedEvents;
+}
+@synthesize characterToCount;
+@synthesize countedCharacters = characterCounter;
+
+
+#pragma mark Object lifecycle
+
+- (id)initWithInputStream:(NSInputStream *)stream
+{
+ self = [super init];
+ if (self) {
+ // Initialization code here.
+ parentStream = [stream retain];
+ [parentStream setDelegate:self];
+ }
+
+ return self;
+}
+
+- (void)dealloc
+{
+ [parentStream release];
+ [super dealloc];
+}
+
+#pragma mark NSStream subclass methods
+
+- (void)open {
+ [parentStream open];
+}
+
+- (void)close {
+ [parentStream close];
+}
+
+- (id <NSStreamDelegate> )delegate {
+ return delegate;
+}
+
+- (void)setDelegate:(id<NSStreamDelegate>)aDelegate {
+ delegate = aDelegate;
+}
+
+- (void)scheduleInRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode {
+ [parentStream scheduleInRunLoop:aRunLoop forMode:mode];
+}
+
+- (void)removeFromRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode {
+ [parentStream removeFromRunLoop:aRunLoop forMode:mode];
+}
+
+- (id)propertyForKey:(NSString *)key {
+ return [parentStream propertyForKey:key];
+}
+
+- (BOOL)setProperty:(id)property forKey:(NSString *)key {
+ return [parentStream setProperty:property forKey:key];
+}
+
+- (NSStreamStatus)streamStatus {
+ return [parentStream streamStatus];
+}
+
+- (NSError *)streamError {
+ return [parentStream streamError];
+}
+
+#pragma mark NSInputStream subclass methods
+
+- (NSInteger)read:(uint8_t *)buffer maxLength:(NSUInteger)len {
+ NSInteger bytesRead = [parentStream read:buffer maxLength:len];
+
+ for (int i=0; i<bytesRead; ++i) {
+ if (buffer[i] == characterToCount) {
+ ++characterCounter;
+ }
+ }
+
+ return bytesRead;
+}
+
+- (BOOL)getBuffer:(uint8_t **)buffer length:(NSUInteger *)len {
+ // We cannot implement our character-counting in O(1) time,
+ // so we return NO as indicated in the NSInputStream
+ // documentation.
+ return NO;
+}
+
+- (BOOL)hasBytesAvailable {
+ return [parentStream hasBytesAvailable];
+}
+
+#pragma mark Undocumented CFReadStream bridged methods
+
+- (void)_scheduleInCFRunLoop:(CFRunLoopRef)aRunLoop forMode:(CFStringRef)aMode {
+
+ CFReadStreamScheduleWithRunLoop((CFReadStreamRef)parentStream, aRunLoop, aMode);
+}
+
+- (BOOL)_setCFClientFlags:(CFOptionFlags)inFlags
+ callback:(CFReadStreamClientCallBack)inCallback
+ context:(CFStreamClientContext *)inContext {
+
+ if (inCallback != NULL) {
+ requestedEvents = inFlags;
+ copiedCallback = inCallback;
+ memcpy(&copiedContext, &inContext, sizeof(CFStreamClientContext));
+
+ if (copiedContext.info && copiedContext.retain) {
+ copiedContext.retain(copiedContext.info);
+ }
+ }
+ else {
+ requestedEvents = kCFStreamEventNone;
+ copiedCallback = NULL;
+ if (copiedContext.info && copiedContext.release) {
+ copiedContext.release(copiedContext.info);
+ }
+
+ memset(&copiedContext, 0, sizeof(CFStreamClientContext));
+ }
+
+ return YES;
+}
+
+- (void)_unscheduleFromCFRunLoop:(CFRunLoopRef)aRunLoop forMode:(CFStringRef)aMode {
+
+ CFReadStreamUnscheduleFromRunLoop((CFReadStreamRef)parentStream, aRunLoop, aMode);
+}
+
+#pragma mark NSStreamDelegate methods
+
+- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode {
+
+ assert(aStream == parentStream);
+
+ switch (eventCode) {
+ case NSStreamEventOpenCompleted:
+ if (requestedEvents & kCFStreamEventOpenCompleted) {
+ copiedCallback((CFReadStreamRef)self,
+ kCFStreamEventOpenCompleted,
+ copiedContext.info);
+ }
+ break;
+
+ case NSStreamEventHasBytesAvailable:
+ if (requestedEvents & kCFStreamEventHasBytesAvailable) {
+ copiedCallback((CFReadStreamRef)self,
+ kCFStreamEventHasBytesAvailable,
+ copiedContext.info);
+ }
+ break;
+
+ case NSStreamEventErrorOccurred:
+ if (requestedEvents & kCFStreamEventErrorOccurred) {
+ copiedCallback((CFReadStreamRef)self,
+ kCFStreamEventErrorOccurred,
+ copiedContext.info);
+ }
+ break;
+
+ case NSStreamEventEndEncountered:
+ if (requestedEvents & kCFStreamEventEndEncountered) {
+ copiedCallback((CFReadStreamRef)self,
+ kCFStreamEventEndEncountered,
+ copiedContext.info);
+ }
+ break;
+
+ case NSStreamEventHasSpaceAvailable:
+ // This doesn't make sense for a read stream
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+@end
Please sign in to comment.
Something went wrong with that request. Please try again.