<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Codethink &#187; hack</title>
	<atom:link href="https://codethink.no-ip.org/tags/hack/feed" rel="self" type="application/rss+xml" />
	<link>https://codethink.no-ip.org</link>
	<description>A blog about coding, life, and other arbitrary topics</description>
	<lastBuildDate>Sun, 15 Mar 2026 21:30:15 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.1.29</generator>
	<item>
		<title>[JavaScript] Finding Equidistant Lat/Long Coordinates</title>
		<link>https://codethink.no-ip.org/archives/746</link>
		<comments>https://codethink.no-ip.org/archives/746#comments</comments>
		<pubDate>Sat, 03 Dec 2011 08:17:52 +0000</pubDate>
		<dc:creator><![CDATA[aroth]]></dc:creator>
				<category><![CDATA[coding]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[hack]]></category>
		<category><![CDATA[location]]></category>
		<category><![CDATA[maps]]></category>

		<guid isPermaLink="false">http://codethink.no-ip.org/wordpress/?p=746</guid>
		<description><![CDATA[Here&#8217;s a quick one that was inspired by a StackOverflow question and built using the references posted here. It allows you to compute the position of an arbitrary number of points (expressed as latitude/longitude pairs) equidistant from a given centerpoint &#8230; <a href="https://codethink.no-ip.org/archives/746">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Here&#8217;s a quick one that was inspired by a <a href="http://stackoverflow.com/questions/6789992/need-to-find-lats-long-of-a-location-which-is-about-50km-away-from-a-location" target="_blank">StackOverflow question</a> and built using the references posted <a href="http://www.movable-type.co.uk/scripts/latlong.html" target="_blank">here</a>.  It allows you to compute the position of an arbitrary number of points (expressed as latitude/longitude pairs) equidistant from a given centerpoint (using a given radius/distance, of course) on the surface of the Earth.  The crux of the code goes like so:</p>
<pre class="brush: jscript; title: ; notranslate">window.pointsAround = function(centerLat, centerLng, radius, numInterpolations) {
    var result = [];

    //do annoying trig maths to work out the delta in latitude between our start and end points
    var targetD = radius;          //km
    var fractionalDistance = (targetD / radiusOfEarth) / 2;
    var sqrtA = Math.sin(fractionalDistance);
    var a = sqrtA * sqrtA;
    var sinHalfDLat = Math.sqrt(a);
    var dLat = Math.asin(sinHalfDLat) * 2;
    var dLatDegrees = degrees(dLat);
    
    var minLat = centerLat - dLatDegrees;              //furthest valid latitude above the origin
    var maxLat = centerLat + dLatDegrees;            //furthest valid latitude below the origin
    
    var centerLatRadians = radians(centerLat); 
    
    //topmost and bottommost points in the circle
    result.push({lat: minLat, lng: centerLng});
    result.push({lat: maxLat, lng: centerLng});
    
    //step from minLat to maxLat, interpolating coordinates that lie upon the circle
    numInterpolations = numInterpolations ? numInterpolations : 360;
    var step = (maxLat - minLat) / (numInterpolations / 2.0);
    for (var count = 0; count &lt; (numInterpolations / 2) - 1; count++) {
        minLat += step;
        var minLatRadians = radians(minLat);
        dLat = radians(centerLat - minLat);
        
        //more annoying trig to work out the delta in longitude for our interpolated coordinate
        var dLon = 2 * Math.asin(Math.sqrt((a - (Math.sin(dLat/2) * Math.sin(dLat/2))) / (Math.cos(minLatRadians) * Math.cos(centerLatRadians))));
        var dLonDegrees = degrees(dLon);
        
        var newLng = centerLng + dLonDegrees;
        var deltaLng = newLng - centerLng;
        result.push({lat: minLat, lng: newLng});
        result.push({lat: minLat, lng: centerLng - deltaLng});
    }
    
    return result;
};</pre>
<p>This code works out the northernmost and southernmost points that are the specified distance away from the given centerpoint.  It then steps between the minimum and maximum latitude of these two points, interpolating the appropriate longitudinal value(s) to satisfy the equidistant constraint.  The total number of coordinates returned can be controlled using the optional &#8216;<em>numInterpolations</em>&#8216; parameter.  When not specified a total of 360 points will be returned by default, because that is a nice, round number.</p>
<p>If you use something like the following code to plot some points on a map:</p>
<pre class="brush: jscript; title: ; notranslate">window.map = new GMap2(document.getElementById(&quot;mapDiv&quot;));
    var centerPoint = new GLatLng(37.4419, -122.1419);
    map.setCenter(centerPoint, 8);
    map.addControl(new GLargeMapControl3D());
    map.addControl(new GMapTypeControl());
    
    var marker = new GMarker(centerPoint);
    var markerText = &quot;Center @ 37.4419, -122.1419&quot;;
    GEvent.addListener(marker, &quot;click&quot;, markerClickHandler(marker, markerText));
    map.addOverlay(marker);
    
    var points = pointsAround(37.4419, -122.1419, 50);
    for (var index = 0; index &lt; points.length; index++) {
        var point = points[index];
        var latlng = new GLatLng(point.lat, point.lng);
        marker = new GMarker(latlng);
        markerText = &quot;Marker @ &quot; + point.lat + &quot;, &quot; + point.lng;
        GEvent.addListener(marker, &quot;click&quot;, markerClickHandler(marker, markerText));
        map.addOverlay(marker);
    }</pre>
<p>&#8230;you will get a nice circle of points around the hard-coded centerpoint.  You can see a working example of this here:  <a href="http://jsfiddle.net/HmchC/27/" target="_blank">http://jsfiddle.net/HmchC/27/</a>.</p>
]]></content:encoded>
			<wfw:commentRss>https://codethink.no-ip.org/archives/746/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>[JavaScript] Creating an Animated Hurricane Tracker</title>
		<link>https://codethink.no-ip.org/archives/773</link>
		<comments>https://codethink.no-ip.org/archives/773#comments</comments>
		<pubDate>Sat, 10 Sep 2011 15:09:21 +0000</pubDate>
		<dc:creator><![CDATA[aroth]]></dc:creator>
				<category><![CDATA[coding]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[hack]]></category>

		<guid isPermaLink="false">http://codethink.no-ip.org/wordpress/?p=773</guid>
		<description><![CDATA[Here&#8217;s a fun little diversion I came up with when the news was all abuzz with information about Hurricane Irene. Now I use Wikipedia almost exclusively for keeping track of this sort of thing as I find that it consistently &#8230; <a href="https://codethink.no-ip.org/archives/773">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Here&#8217;s a fun little diversion I came up with when the news was all abuzz with information about <a href="http://en.wikipedia.org/wiki/Hurricane_Irene_(2011)" target="_blank">Hurricane Irene</a>.  Now I use Wikipedia almost exclusively for keeping track of this sort of thing as I find that it consistently provides the most up to date data in the cleanest and most easy to digest format, but I also noticed a large volume of comments on other news sites complaining about the accuracy of hurricane forecasting.  And this got me to wondering, just how accurate are the historical forecasts when overlaid with the actual storm track?</p>
<p>Well Wikipedia doesn&#8217;t provide this information directly, but interestingly enough Wikipedia does in fact keep all the <a href="http://en.wikipedia.org/w/index.php?title=File:09L_2011_5day.gif&#038;limit=500#filehistory" target="_blank">historical data</a> necessary to answer this question.  Thanks to Chrome&#8217;s awesome JavaScript console (and the fact that Wikipedia uses jQuery on all of its pages) it is a very simple matter to extract this historical information in a format that is easy to work with later.  The following code will do the trick:</p>
<pre class="brush: jscript; title: ; notranslate">var result = []; 
jQuery.each($(&quot;.filehistory a[href$=5day.gif]&quot;), function(){
    result.push(this.href)
}); 
result;</pre>
<p>This simply constructs an array containing the URL&#8217;s of every historical forecast/storm track graphic (ordered by date from newest to oldest) and outputs it to the console.  We can then copy/paste the console output to wherever we like, such as <a href="http://jsfiddle.net" target="_blank">jsFiddle</a> for instance.  Combine this with some basic HTML structure:</p>
<pre class="brush: xml; title: ; notranslate">&lt;div class=&quot;title&quot;&gt;
    Hurricane Irene Animated Forecast Map
&lt;/div&gt;
&lt;img id=&quot;display&quot; src=&quot;http://fcf.teambeachbody.com/fcf/images/spinner5.gif&quot; /&gt;
&lt;div id=&quot;status&quot;&gt;
    (&lt;span id=&quot;numLoaded&quot;&gt;&lt;/span&gt; of &lt;span id=&quot;total&quot;&gt;&lt;/span&gt; frames loaded)
&lt;/div&gt;</pre>
<p>&#8230;and some simple JavaScript to handle the actual rendering:</p>
<pre class="brush: jscript; title: ; notranslate">document.getElementById(&quot;numLoaded&quot;).innerHTML = &quot;0&quot;;
document.getElementById(&quot;total&quot;).innerHTML = data.length;

//preload all the images so that they are cached for the animation
window.imagesLoaded = 0;
for (var index = data.length - 1; index &gt;= 0; index--) {
    var node = document.createElement(&quot;img&quot;);
    node.style.display = &quot;none&quot;;
    document.body.appendChild(node);
    $(node).bind('load', function() {  
        window.imagesLoaded++;  
    });
    $(node).attr('src', data[index]);
    //node.src = data[index];
}

//run the animation
window.currentImage = data.length - 1;
window.updateAnimation = function() {
    if (window.imagesLoaded &lt; data.length) {
        //keep waiting
        document.getElementById(&quot;numLoaded&quot;).innerHTML = window.imagesLoaded;
        return;
    }
    $(&quot;#status&quot;).hide();
    document.getElementById(&quot;display&quot;).src = data[currentImage];
    currentImage--;
    if (currentImage &lt; 0) {
        currentImage = data.length - 1;
    }
};

setInterval(updateAnimation, 200);</pre>
<p>&#8230;and you get an animated map of the entire forecast history, including the actual storm track.  The result looks something like this:</p>
<p><iframe src="http://fiddle.jshell.net/TqmVg/6/show/" width="425" height="380" frameBorder="0"><br />
</iframe></p>
<p>Not too bad for a few dozen lines of code and about 30 minutes worth of effort.  You can also access a full-scale, editable version of this animated storm history <a href="http://jsfiddle.net/TqmVg/5/" target="_blank">here</a>.</p>
<p>So what does this say about the accuracy of the hurricane forecasting for Irene?  Personally I think it shows that the forecasts are pretty damn accurate.  In fact, if you focus just on the solid white portion of the predicted storm track it appears that the storm never deviates from its forecast path.  It&#8217;s only when looking at the dashed white portion of the forecast that any significant deviation can be noted.  And the dashed white portion indicates forecasts that are more than 72 hours in the future.  </p>
<p>Of course we should always be working to improve our ability to predict and forecast these things, but I have to think that being able to accurately predict a storm&#8217;s movement for up to 72 hours into the future is adequate for most purposes.</p>
]]></content:encoded>
			<wfw:commentRss>https://codethink.no-ip.org/archives/773/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Resurrecting sun.misc.Unsafe</title>
		<link>https://codethink.no-ip.org/archives/712</link>
		<comments>https://codethink.no-ip.org/archives/712#comments</comments>
		<pubDate>Sat, 09 Jul 2011 15:21:48 +0000</pubDate>
		<dc:creator><![CDATA[aroth]]></dc:creator>
				<category><![CDATA[coding]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[hack]]></category>

		<guid isPermaLink="false">http://codethink.no-ip.org/wordpress/?p=712</guid>
		<description><![CDATA[Here&#8217;s one that only the hardcore Java hackers will enjoy. Perhaps you are already familiar with sun.misc.Unsafe. This heavily protected internal class provides access to a number of low-level memory operations and system functions that are generally hidden away from &#8230; <a href="https://codethink.no-ip.org/archives/712">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Here&#8217;s one that only the hardcore Java hackers will enjoy.  Perhaps you are already familiar with <a href="http://www.docjar.com/docs/api/sun/misc/Unsafe.html" target="_blank">sun.misc.Unsafe</a>.  This heavily protected internal class provides access to a number of low-level memory operations and system functions that are generally hidden away from user-code executing in the JRE.  If you&#8217;ve never heard of it before (or even if you have) then I encourage you to read this <a href="http://javapapers.com/core-java/address-of-a-java-object/" target="_blank">article</a> to get an idea about the sort of things that can be done using &#8216;<em>Unsafe</em>&#8216;.  Note that we are talking about very low-level operations here.  Operations where if you make a mistake, you won&#8217;t just get a simple &#8216;<em>Exception</em>&#8216; complaining that you did something bad.  Instead you&#8217;re liable to bring the entire JVM to a crashing halt if you do something wrong (it&#8217;s called &#8216;<em>Unsafe</em>&#8216; for a reason, after all), so you should proceed only if you&#8217;re sure you know what you are doing.</p>
<p>Also note that the method described in the <a href="http://javapapers.com/core-java/address-of-a-java-object/" target="_blank">other article</a> for getting your hands on an instance of &#8216;<em>Unsafe</em>&#8216; no longer works.  Using the latest JDK, the following code will not work (you&#8217;ll get compiler errors for even trying to <em>import</em> sun.misc.Unsafe):</p>
<pre class="brush: java; title: ; notranslate">private static Unsafe getUnsafeInstance() throws SecurityException, NoSuchFieldException, IllegalArgumentException,
    IllegalAccessException {
    Field theUnsafeInstance = Unsafe.class.getDeclaredField(&quot;theUnsafe&quot;);
    theUnsafeInstance.setAccessible(true);
    return (Unsafe) theUnsafeInstance.get(Unsafe.class);
 }</pre>
<p>Here is a variant that still works:</p>
<pre class="brush: java; title: ; notranslate">	public static Object getUnsafe() {
		try {
			Class unsafeClass = Class.forName(&quot;sun.misc.Unsafe&quot;);
			Field unsafeField = unsafeClass.getDeclaredField(&quot;theUnsafe&quot;);
			unsafeField.setAccessible(true);
			Object unsafeObj = unsafeField.get(unsafeClass);
			
			return unsafeObj;
		}
		catch (Exception e) {
			return null;//UNSAFE_ERROR_CODE;
		}
	}</pre>
<p>Note that as importing sun.misc.Unsafe now causes a compiler error, it is only possible to return an Object reference to the &#8216;<em>Unsafe</em>&#8216; instance.  This means that any method that you want to call on it must be done through reflection, which is tedious at best.  Luckily, I&#8217;ve taken care of this tedious bit for you, and created a wrapper that provides the same public API as sun.misc.Unsafe and uses reflection to delegate method calls to the real &#8216;<em>Unsafe</em>&#8216; instance.  The source code for this utility is quite long and not very interesting, so I&#8217;m not going to post it here.  Instead you can use this <a href="http://aroth.no-ip.org/UnsafeUtil.java">direct link</a> to download a copy.</p>
<p>Here is a simple example of how to use this class to perform some basic tasks:</p>
<pre class="brush: java; title: ; notranslate">		System.out.println(&quot;Testing sun.misc.Unsafe...&quot;);
		double[] averages = {-777.0, -777.0, -777.0};
		UnsafeUtil util = new UnsafeUtil();
		System.out.println(&quot;addressSize=&quot; + util.addressSize() + &quot;, pageSize=&quot; + util.pageSize());
		
		long memPointer = util.allocateMemory(1024);
		long memPointer2 = util.allocateMemory(1024);
		System.out.println(&quot;1K memory blocks at addresses:  &quot; + memPointer + &quot;, &quot; + memPointer2);
		
		//valid copy
		util.copyMemory(memPointer, memPointer2, 1024);
		
		//invalid copy
		//util.copyMemory(memPointer, memPointer2, 1024000);
		
		int result = util.getLoadAverage(averages, 1);
		System.out.println(&quot;getLoadAverage:  Result=&quot; + result + &quot;, averages=&quot; + averages[0] + &quot;, &quot; + averages[1] + &quot;, &quot; + averages[2]);</pre>
<p>Do note that if you uncomment the &#8220;invalid copy&#8221; line then running this code will very likely crash your JVM.  As noted above, you should use this utility with caution, particularly if you are running it in an environment shared by other Java code.</p>
<p>And why do all this when Sun (now Oracle) clearly does not want people mucking around with this class?  Because ultimately power belongs in the hands of developers.  All developers, not just the select few chosen to work on privileged system code.</p>
]]></content:encoded>
			<wfw:commentRss>https://codethink.no-ip.org/archives/712/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>[Objective-C + Cocoa] iPhone Screen Capture Revisited</title>
		<link>https://codethink.no-ip.org/archives/673</link>
		<comments>https://codethink.no-ip.org/archives/673#comments</comments>
		<pubDate>Wed, 15 Jun 2011 13:36:12 +0000</pubDate>
		<dc:creator><![CDATA[aroth]]></dc:creator>
				<category><![CDATA[coding]]></category>
		<category><![CDATA[objective-c]]></category>
		<category><![CDATA[hack]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[recording]]></category>
		<category><![CDATA[video]]></category>

		<guid isPermaLink="false">http://codethink.no-ip.org/wordpress/?p=673</guid>
		<description><![CDATA[Awhile back I posted a handful of simple iOS utilities. Among them was a basic ScreenCaptureView implementation that would periodically render the contents of its subview(s) into a UIImage that was exposed as a publicly accessible property. This provides the &#8230; <a href="https://codethink.no-ip.org/archives/673">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Awhile back I posted a handful of simple <a href="http://codethink.no-ip.org/wordpress/archives/541">iOS utilities</a>.  Among them was a basic <em>ScreenCaptureView</em> implementation that would periodically render the contents of its subview(s) into a <em>UIImage</em> that was exposed as a publicly accessible property.  This provides the ability to quickly and easily take a snapshot of your running application, or any arbitrary component within it.  And while not superbly impressive (the iPhone has a built-in screenshot feature, after all), I noted that the control theoretically allowed for captured frames to be sent off to an <em>AVCaptureSession</em> in order to record live video of a running application.  </p>
<p>Recently I returned to this bit of code, and the ability to record live video of an application is theoretical no longer.  To get straight to the point, here is the revised code:</p>
<pre class="brush: cpp; title: ; notranslate">//
//ScreenCaptureView.h
//
#import &lt;UIKit/UIKit.h&gt;
#import &lt;AVFoundation/AVFoundation.h&gt;

/**
 * Delegate protocol.  Implement this if you want to receive a notification when the
 * view completes a recording.
 *
 * When a recording is completed, the ScreenCaptureView will notify the delegate, passing
 * it the path to the created recording file if the recording was successful, or a value
 * of nil if the recording failed/could not be saved.
 */
@protocol ScreenCaptureViewDelegate &lt;NSObject&gt;
- (void) recordingFinished:(NSString*)outputPathOrNil;
@end


/**
 * ScreenCaptureView, a UIView subclass that periodically samples its current display
 * and stores it as a UIImage available through the 'currentScreen' property.  The
 * sample/update rate can be configured (within reason) by setting the 'frameRate'
 * property.
 *
 * This class can also be used to record real-time video of its subviews, using the
 * 'startRecording' and 'stopRecording' methods.  A new recording will overwrite any
 * previously made recording file, so if you want to create multiple recordings per
 * session (or across multiple sessions) then it is your responsibility to copy/back-up
 * the recording output file after each session.
 *
 * To use this class, you must link against the following frameworks:
 *
 *  - AssetsLibrary
 *  - AVFoundation
 *  - CoreGraphics
 *  - CoreMedia
 *  - CoreVideo
 *  - QuartzCore
 *
 */

@interface ScreenCaptureView : UIView {
   //video writing
   AVAssetWriter *videoWriter;
   AVAssetWriterInput *videoWriterInput;
   AVAssetWriterInputPixelBufferAdaptor *avAdaptor;

   //recording state
   BOOL _recording;
   NSDate* startedAt;
   void* bitmapData;
}

//for recording video
- (bool) startRecording;
- (void) stopRecording;

//for accessing the current screen and adjusting the capture rate, etc.
@property(retain) UIImage* currentScreen;
@property(assign) float frameRate;
@property(nonatomic, assign) id&lt;ScreenCaptureViewDelegate&gt; delegate;

@end



//
//ScreenCaptureView.m
//
#import &quot;ScreenCaptureView.h&quot;
#import &lt;QuartzCore/QuartzCore.h&gt;
#import &lt;MobileCoreServices/UTCoreTypes.h&gt;
#import &lt;AssetsLibrary/AssetsLibrary.h&gt;

@interface ScreenCaptureView(Private)
- (void) writeVideoFrameAtTime:(CMTime)time;
@end


@implementation ScreenCaptureView

@synthesize currentScreen, frameRate, delegate;

- (void) initialize {
   // Initialization code
   self.clearsContextBeforeDrawing = YES;
   self.currentScreen = nil;
   self.frameRate = 10.0f;     //10 frames per seconds
   _recording = false;
   videoWriter = nil;
   videoWriterInput = nil;
   avAdaptor = nil;
   startedAt = nil;
   bitmapData = NULL;
}

- (id) initWithCoder:(NSCoder *)aDecoder {
   self = [super initWithCoder:aDecoder];
   if (self) {
       [self initialize];
   }
   return self;
}

- (id) init {
   self = [super init];
   if (self) {
       [self initialize];
   }
   return self;
}

- (id)initWithFrame:(CGRect)frame {
   self = [super initWithFrame:frame];
   if (self) {
       [self initialize];
   }
   return self;
}

- (CGContextRef) createBitmapContextOfSize:(CGSize) size {
   CGContextRef    context = NULL;
   CGColorSpaceRef colorSpace;
   int             bitmapByteCount;
   int             bitmapBytesPerRow;

   bitmapBytesPerRow   = (size.width * 4);
   bitmapByteCount     = (bitmapBytesPerRow * size.height);
   colorSpace = CGColorSpaceCreateDeviceRGB();
   if (bitmapData != NULL) {
       free(bitmapData);
   }
   bitmapData = malloc( bitmapByteCount );
   if (bitmapData == NULL) {
       fprintf (stderr, &quot;Memory not allocated!&quot;);
       return NULL;
   }

   context = CGBitmapContextCreate (bitmapData,
                                    size.width,
                                    size.height,
                                    8,      // bits per component
                                    bitmapBytesPerRow,
                                    colorSpace,
                                    kCGImageAlphaNoneSkipFirst);

   CGContextSetAllowsAntialiasing(context,NO);
   if (context== NULL) {
       free (bitmapData);
       fprintf (stderr, &quot;Context not created!&quot;);
       return NULL;
   }
   CGColorSpaceRelease( colorSpace );

   return context;
}


//static int frameCount = 0;            //debugging
- (void) drawRect:(CGRect)rect {
   NSDate* start = [NSDate date];
   CGContextRef context = [self createBitmapContextOfSize:self.frame.size];
   
   //not sure why this is necessary...image renders upside-down and mirrored
   CGAffineTransform flipVertical = CGAffineTransformMake(1, 0, 0, -1, 0, self.frame.size.height);
   CGContextConcatCTM(context, flipVertical);

   [self.layer renderInContext:context];
   
   CGImageRef cgImage = CGBitmapContextCreateImage(context);
   UIImage* background = [UIImage imageWithCGImage: cgImage];
   CGImageRelease(cgImage);
   
   self.currentScreen = background;

   //debugging
   //if (frameCount &lt; 40) {
   //      NSString* filename = [NSString stringWithFormat:@&quot;Documents/frame_%d.png&quot;, frameCount];
   //      NSString* pngPath = [NSHomeDirectory() stringByAppendingPathComponent:filename];
   //      [UIImagePNGRepresentation(self.currentScreen) writeToFile: pngPath atomically: YES];
   //      frameCount++;
   //}

   //NOTE:  to record a scrollview while it is scrolling you need to implement your UIScrollViewDelegate such that it calls
   //       'setNeedsDisplay' on the ScreenCaptureView.
   if (_recording) {
       float millisElapsed = [[NSDate date] timeIntervalSinceDate:startedAt] * 1000.0;
       [self writeVideoFrameAtTime:CMTimeMake((int)millisElapsed, 1000)];
   }

   float processingSeconds = [[NSDate date] timeIntervalSinceDate:start];
   float delayRemaining = (1.0 / self.frameRate) - processingSeconds;

   CGContextRelease(context);

   //redraw at the specified framerate
   [self performSelector:@selector(setNeedsDisplay) withObject:nil afterDelay:delayRemaining &gt; 0.0 ? delayRemaining : 0.01];   
}

- (void) cleanupWriter {
   [avAdaptor release];
   avAdaptor = nil;
   
   [videoWriterInput release];
   videoWriterInput = nil;
   
   [videoWriter release];
   videoWriter = nil;
   
   [startedAt release];
   startedAt = nil;

   if (bitmapData != NULL) {
       free(bitmapData);
       bitmapData = NULL;
   }
}

- (void)dealloc {
   [self cleanupWriter];
   [super dealloc];
}

- (NSURL*) tempFileURL {
   NSString* outputPath = [[NSString alloc] initWithFormat:@&quot;%@/%@&quot;, [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0], @&quot;output.mp4&quot;];
   NSURL* outputURL = [[NSURL alloc] initFileURLWithPath:outputPath];
   NSFileManager* fileManager = [NSFileManager defaultManager];
   if ([fileManager fileExistsAtPath:outputPath]) {
       NSError* error;
       if ([fileManager removeItemAtPath:outputPath error:&amp;error] == NO) {
           NSLog(@&quot;Could not delete old recording file at path:  %@&quot;, outputPath);
       }
   }

   [outputPath release];
   return [outputURL autorelease];
}

-(BOOL) setUpWriter {
   NSError* error = nil;
   videoWriter = [[AVAssetWriter alloc] initWithURL:[self tempFileURL] fileType:AVFileTypeQuickTimeMovie error:&amp;error];
   NSParameterAssert(videoWriter);

   //Configure video
   NSDictionary* videoCompressionProps = [NSDictionary dictionaryWithObjectsAndKeys:
                                          [NSNumber numberWithDouble:1024.0*1024.0], AVVideoAverageBitRateKey,
                                          nil ];

   NSDictionary* videoSettings = [NSDictionary dictionaryWithObjectsAndKeys:
                                  AVVideoCodecH264, AVVideoCodecKey,
                                  [NSNumber numberWithInt:self.frame.size.width], AVVideoWidthKey,
                                  [NSNumber numberWithInt:self.frame.size.height], AVVideoHeightKey,
                                  videoCompressionProps, AVVideoCompressionPropertiesKey,
                                  nil];

   videoWriterInput = [[AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:videoSettings] retain];

   NSParameterAssert(videoWriterInput);
   videoWriterInput.expectsMediaDataInRealTime = YES;
   NSDictionary* bufferAttributes = [NSDictionary dictionaryWithObjectsAndKeys: 
                                     [NSNumber numberWithInt:kCVPixelFormatType_32ARGB], kCVPixelBufferPixelFormatTypeKey, nil];

   avAdaptor = [[AVAssetWriterInputPixelBufferAdaptor assetWriterInputPixelBufferAdaptorWithAssetWriterInput:videoWriterInput sourcePixelBufferAttributes:bufferAttributes] retain];

   //add input
   [videoWriter addInput:videoWriterInput];
   [videoWriter startWriting];
   [videoWriter startSessionAtSourceTime:CMTimeMake(0, 1000)];

   return YES;
}



- (void) completeRecordingSession {
   NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];

   [videoWriterInput markAsFinished];
   
   // Wait for the video
   int status = videoWriter.status;
   while (status == AVAssetWriterStatusUnknown) {
       NSLog(@&quot;Waiting...&quot;);
       [NSThread sleepForTimeInterval:0.5f];
       status = videoWriter.status;
   }

   @synchronized(self) {
       BOOL success = [videoWriter finishWriting];
       if (!success) {
           NSLog(@&quot;finishWriting returned NO&quot;);
       }

       [self cleanupWriter];

       id delegateObj = self.delegate;
       NSString *outputPath = [[NSString alloc] initWithFormat:@&quot;%@/%@&quot;, [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0], @&quot;output.mp4&quot;];
       NSURL *outputURL = [[NSURL alloc] initFileURLWithPath:outputPath];

       NSLog(@&quot;Completed recording, file is stored at:  %@&quot;, outputURL);
       if ([delegateObj respondsToSelector:@selector(recordingFinished:)]) {
           [delegateObj performSelectorOnMainThread:@selector(recordingFinished:) withObject:(success ? outputURL : nil) waitUntilDone:YES];
       }

       [outputPath release];
       [outputURL release];
   }

   [pool drain];
}



- (bool) startRecording {
   bool result = NO;
   @synchronized(self) {
       if (! _recording) {
           result = [self setUpWriter];
           startedAt = [[NSDate date] retain];
           _recording = true;
       }
   }

   return result;
}

- (void) stopRecording {
   @synchronized(self) {
       if (_recording) {
           _recording = false;
           [self completeRecordingSession];
       }
   }
}

-(void) writeVideoFrameAtTime:(CMTime)time {
   if (![videoWriterInput isReadyForMoreMediaData]) {
       NSLog(@&quot;Not ready for video data&quot;);
   }
   else {
       @synchronized (self) {
           UIImage* newFrame = [self.currentScreen retain];
           CVPixelBufferRef pixelBuffer = NULL;
           CGImageRef cgImage = CGImageCreateCopy([newFrame CGImage]);
           CFDataRef image = CGDataProviderCopyData(CGImageGetDataProvider(cgImage));

           int status = CVPixelBufferPoolCreatePixelBuffer(kCFAllocatorDefault, avAdaptor.pixelBufferPool, &amp;pixelBuffer);
           if(status != 0){
               //could not get a buffer from the pool
               NSLog(@&quot;Error creating pixel buffer:  status=%d&quot;, status);
           }
                       // set image data into pixel buffer
           CVPixelBufferLockBaseAddress( pixelBuffer, 0 );
           uint8_t* destPixels = CVPixelBufferGetBaseAddress(pixelBuffer);
           CFDataGetBytes(image, CFRangeMake(0, CFDataGetLength(image)), destPixels);  //XXX:  will work if the pixel buffer is contiguous and has the same bytesPerRow as the input data

           if(status == 0){
               BOOL success = [avAdaptor appendPixelBuffer:pixelBuffer withPresentationTime:time];
               if (!success)
                   NSLog(@&quot;Warning:  Unable to write buffer to video&quot;);
           }

           //clean up
           [newFrame release];
           CVPixelBufferUnlockBaseAddress( pixelBuffer, 0 );
           CVPixelBufferRelease( pixelBuffer );        
           CFRelease(image);
           CGImageRelease(cgImage);
       }

   }

}

@end</pre>
<p>This class will let you record high-quality video of any other view in your application.  To use it, simply set it up as the superview of the <em>UIView(s)</em> that you want to record, add a reference to it in your corresponding <em>UIViewController</em> (using Interface Builder or whatever your preferred method happens to be), and then call &#8216;<em>startRecording</em>&#8216; when you are ready to start recording video.  When you&#8217;ve recorded enough, call &#8216;<em>stopRecording</em>&#8216; to complete the process.  You will get a nice .mp4 file stored under your application&#8217;s &#8216;Documents&#8217; directory that you can copy off or do whatever else you want with.</p>
<p>Note that if you want to record a <em>UIScrollView</em> while it is scrolling, you will need to implement your <em>UIScrollViewDelegate</em> such that it calls &#8216;<em>setNeedsDisplay</em>&#8216; on the <em>ScreenCaptureView</em> while the scroll-view is scrolling.  For instance:</p>
<pre class="brush: cpp; title: ; notranslate">- (void) scrollViewDidScroll: (UIScrollView*)scrollView {
       [captureView setNeedsDisplay];
}</pre>
<p>I haven&#8217;t tested this code on a physical device yet, but there&#8217;s no reason why it should not work on any device that includes H.264 video codec support (iPhone 3GS and later).  However, given the amount of drawing that it does, it&#8217;s safe to say that the more horsepower behind it, the better.  </p>
<p>Here is a rather unimpressive 30-second recording of a <em>UITableView</em> that I created using this class (if your browser doesn&#8217;t support HTML5, use the link below):<br />
<video width="320" height="460" controls><source src="http://codethink.no-ip.org/wordpress/wp-content/uploads/2011/06/output.mp4"></video><br />
<a href='http://codethink.no-ip.org/wordpress/wp-content/uploads/2011/06/output.mp4' target="_blank">Example iPhone Recording</a></p>
<p>Lastly, I haven&#8217;t tested this class with any OpenGL-based subviews, so I can&#8217;t say if it will work in that case.  If you try it in this configuration, please feel free to reply with your results.</p>
<p><strong>Update</strong></p>
<p>For anyone looking for a working example, you can download this <a href="http://codethink.no-ip.org/ScreenCaptureViewTest.zip">sample project</a>.  This project simply creates a 30-second recording of a &#8216;<em>UITableView</em>&#8216;.</p>
]]></content:encoded>
			<wfw:commentRss>https://codethink.no-ip.org/archives/673/feed</wfw:commentRss>
		<slash:comments>156</slash:comments>
<enclosure url="http://codethink.no-ip.org/wordpress/wp-content/uploads/2011/06/output.mp4" length="700174" type="video/mp4" />
		</item>
		<item>
		<title>[Java] Override HTTP Request Parameters</title>
		<link>https://codethink.no-ip.org/archives/634</link>
		<comments>https://codethink.no-ip.org/archives/634#comments</comments>
		<pubDate>Sun, 15 May 2011 07:25:39 +0000</pubDate>
		<dc:creator><![CDATA[aroth]]></dc:creator>
				<category><![CDATA[coding]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[hack]]></category>

		<guid isPermaLink="false">http://codethink.no-ip.org/wordpress/?p=634</guid>
		<description><![CDATA[Often in a Java web-application I come across cases where it would be useful to directly override or modify one or more HTTP request parameters. To be clear, by &#8220;request parameter&#8221; I am referring to the value that is returned &#8230; <a href="https://codethink.no-ip.org/archives/634">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Often in a Java web-application I come across cases where it would be useful to directly override or modify one or more HTTP request parameters.  To be clear, by &#8220;request parameter&#8221; I am referring to the value that is returned by the <a href="http://tomcat.apache.org/tomcat-5.5-doc/servletapi/javax/servlet/ServletRequest.html" target="_blank">ServletRequest</a>&#8216;s &#8216;<em>getParameter()</em>&#8216; method.  For whatever reason the architects of the Servlet spec decided that direct modification of request parameters was not to be supported, despite the number of use-cases that can benefit from such a feature.</p>
<p>For example, say that you have a <a href="http://download.oracle.com/javaee/5/api/javax/servlet/Filter.html" target="_blank">Filter</a> that you are using to sanitize input parameters and guard against things like <a href="http://en.wikipedia.org/wiki/Cross-site_scripting" target="_blank">XSS attacks</a> by ensuring that obviously invalid values like &#8220;&lt;script&gt;alert(&#8216;hacked!&#8217;);&lt;/script&gt;&#8221; are filtered out.  Wouldn&#8217;t it be great if you could implement your Filter such that when it finds one or more forbidden values it flags the request as potentially malicious (using a request attribute), removes any parameters that contain potentially unsafe data, and relocates the potentially unsafe data to a predetermined quarantine area (also accessible via a request attribute)?  This would protect your webapp code from ever receiving a malicious parameter, while still allowing parts of the code that might permit seemingly malicious parameters (for instance, there is no reason to prevent a user from registering with a password of &#8220;&lt;script&gt;alert(&#8216;hacked!&#8217;);&lt;/script&gt;&#8221; if that is what they want to use, particularly if you are hashing user passwords like you should be) to still access them if desired by going through the quarantine area.  </p>
<p>Of course, two-thirds of the functionality described above can be implemented without being able to override request parameters.  With the standard API you can certainly check for potentially malicious parameters, set an attribute if you find any, and copy their values into a quarantine area.  But what you cannot do is remove the parameters from the request, so any application code that directly accesses a request parameter value may still be at risk, particularly if its author forgets to check to see if the request has been flagged as suspect.  The real beauty of being able to override parameter values is that you can do things like completely prevent a malicious parameter from ever being visible to your application code unless your application code goes out of its way to look for it (and if you do that, and you do it incorrectly, then that&#8217;s your own fault).  </p>
<p>Anyways, the code to enable this kind of functionality is a fairly straightforward (if tedious) exercise in writing an HttpServletRequest wrapper and then overriding a few choice methods (and adding a couple new ones):  </p>
<pre class="brush: java; title: ; notranslate">import java.io.BufferedReader;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.Principal;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletInputStream;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

public class OverridableHttpRequest implements HttpServletRequest {
        
	private HttpServletRequest wrappedRequest;
	private Map&lt;String, String&gt; newParams;
	private Set&lt;String&gt; removedParams;

	public OverridableHttpRequest(HttpServletRequest requestToWrap) {
		this.wrappedRequest = requestToWrap;
		this.newParams = new HashMap&lt;String, String&gt;();
		this.removedParams = new HashSet&lt;String&gt;();
	}

	// these things we add so that params can be overridden
	public void setParameter(String name, String value) {
		this.removedParams.remove(name);
		this.newParams.put(name, value);
	}

	public void removeParameter(String name) {
		this.newParams.remove(name);
		this.removedParams.add(name);
	}

	// these things we need to override so that the correct state is exposed through the standard API
	@SuppressWarnings(&quot;rawtypes&quot;)
	@Override
	public Enumeration getParameterNames() {
		Set&lt;String&gt; result = new HashSet&lt;String&gt;();
		Enumeration requestParams = this.wrappedRequest.getParameterNames();
		while (requestParams.hasMoreElements()) {
			Object param = requestParams.nextElement();
			if (!removedParams.contains(param)) {
				result.add((String) param);
			}
		}
		result.addAll(newParams.keySet());

		return Collections.enumeration(result);
	}

	@Override
	public String[] getParameterValues(String arg0) {
		//NOTE:  not strictly to spec
		String[] result = new String[1];
		result[0] = this.getParameter(arg0);

		return result;
	}

	@Override
	public String getParameter(String arg0) {
		if (removedParams.contains(arg0)) {
			return null;
		}
		if (newParams.containsKey(arg0)) {
			return newParams.get(arg0);
		}
		return this.wrappedRequest.getParameter(arg0);
	}

	@SuppressWarnings(&quot;rawtypes&quot;)
	@Override
	public Map getParameterMap() {
		Map&lt;String, String[]&gt; result = new HashMap&lt;String, String[]&gt;();
		for (Object key : this.wrappedRequest.getParameterMap().keySet()) {
			result.put((String)key, (String[])this.wrappedRequest.getParameterMap().get(key));
		}
		for (String key : this.newParams.keySet()) {
			result.put(key, new String[] {this.newParams.get(key)});
		}
		for (String key : this.removedParams) {
			result.remove(key);
		}
		
		return result;
	}

	// these things we should probably override but don't right now
	@Override
	public String getRequestURI() {
		// FIXME: should return a modified URI based upon current state
		return this.wrappedRequest.getRequestURI();
	}

	@Override
	public StringBuffer getRequestURL() {
		// FIXME: should return a modified URL based upon current state
		return this.wrappedRequest.getRequestURL();
	}

	@Override
	public String getQueryString() {
		// FIXME: should return a modified String based upon current state
		return this.wrappedRequest.getQueryString();
	}

	// everything else just passes through
	@Override
	public Object getAttribute(String arg0) {
		return this.wrappedRequest.getAttribute(arg0);
	}

	@SuppressWarnings(&quot;rawtypes&quot;)
	@Override
	public Enumeration getAttributeNames() {
		return this.wrappedRequest.getAttributeNames();
	}

	@Override
	public String getCharacterEncoding() {
		return this.wrappedRequest.getCharacterEncoding();
	}

	@Override
	public int getContentLength() {
		return this.wrappedRequest.getContentLength();
	}

	@Override
	public String getContentType() {
		return this.wrappedRequest.getContentType();
	}

	@Override
	public ServletInputStream getInputStream() throws IOException {
		return this.wrappedRequest.getInputStream();
	}

	@Override
	public String getLocalAddr() {
		return this.wrappedRequest.getLocalAddr();
	}

	@Override
	public String getLocalName() {
		return this.wrappedRequest.getLocalName();
	}

	@Override
	public int getLocalPort() {
		return this.wrappedRequest.getLocalPort();
	}

	@Override
	public Locale getLocale() {
		return this.wrappedRequest.getLocale();
	}

	@SuppressWarnings(&quot;rawtypes&quot;)
	@Override
	public Enumeration getLocales() {
		return this.wrappedRequest.getLocales();
	}

	@Override
	public String getProtocol() {
		return this.wrappedRequest.getProtocol();
	}

	@Override
	public BufferedReader getReader() throws IOException {
		return this.wrappedRequest.getReader();
	}

	@SuppressWarnings(&quot;deprecation&quot;)
	@Override
	public String getRealPath(String arg0) {
		return this.wrappedRequest.getRealPath(arg0);
	}

	@Override
	public String getRemoteAddr() {
		return this.wrappedRequest.getRemoteAddr();
	}

	@Override
	public String getRemoteHost() {
		return this.wrappedRequest.getRemoteHost();
	}

	@Override
	public int getRemotePort() {
		return this.wrappedRequest.getRemotePort();
	}

	@Override
	public RequestDispatcher getRequestDispatcher(String arg0) {
		return this.wrappedRequest.getRequestDispatcher(arg0);
	}

	@Override
	public String getScheme() {
		return this.wrappedRequest.getScheme();
	}

	@Override
	public String getServerName() {
		return this.wrappedRequest.getServerName();
	}

	@Override
	public int getServerPort() {
		return this.wrappedRequest.getServerPort();
	}

	@Override
	public boolean isSecure() {
		return this.wrappedRequest.isSecure();
	}

	@Override
	public void removeAttribute(String arg0) {
		this.wrappedRequest.removeAttribute(arg0);
	}

	@Override
	public void setAttribute(String arg0, Object arg1) {
		this.wrappedRequest.setAttribute(arg0, arg1);
	}

	@Override
	public void setCharacterEncoding(String arg0)
			throws UnsupportedEncodingException {
		this.wrappedRequest.setCharacterEncoding(arg0);
	}

	@Override
	public String getAuthType() {
		return this.wrappedRequest.getAuthType();
	}

	@Override
	public String getContextPath() {
		return this.wrappedRequest.getContextPath();
	}

	@Override
	public Cookie[] getCookies() {
		return this.wrappedRequest.getCookies();
	}

	@Override
	public long getDateHeader(String arg0) {
		return this.wrappedRequest.getDateHeader(arg0);
	}

	@Override
	public String getHeader(String arg0) {
		return this.wrappedRequest.getHeader(arg0);
	}

	@SuppressWarnings(&quot;rawtypes&quot;)
	@Override
	public Enumeration getHeaderNames() {
		return this.wrappedRequest.getHeaderNames();
	}

	@SuppressWarnings(&quot;rawtypes&quot;)
	@Override
	public Enumeration getHeaders(String arg0) {
		return this.wrappedRequest.getHeaders(arg0);
	}

	@Override
	public int getIntHeader(String arg0) {
		return this.wrappedRequest.getIntHeader(arg0);
	}

	@Override
	public String getMethod() {
		return this.wrappedRequest.getMethod();
	}

	@Override
	public String getPathInfo() {
		return this.wrappedRequest.getPathInfo();
	}

	@Override
	public String getPathTranslated() {
		return this.wrappedRequest.getPathTranslated();
	}

	@Override
	public String getRemoteUser() {
		return this.wrappedRequest.getRemoteUser();
	}

	@Override
	public String getRequestedSessionId() {
		return this.wrappedRequest.getRequestedSessionId();
	}

	@Override
	public String getServletPath() {
		return this.wrappedRequest.getServletPath();
	}

	@Override
	public HttpSession getSession() {
		return this.wrappedRequest.getSession();
	}

	@Override
	public HttpSession getSession(boolean arg0) {
		return this.wrappedRequest.getSession(arg0);
	}

	@Override
	public Principal getUserPrincipal() {
		return this.wrappedRequest.getUserPrincipal();
	}

	@Override
	public boolean isRequestedSessionIdFromCookie() {
		return this.wrappedRequest.isRequestedSessionIdFromCookie();
	}

	@Override
	public boolean isRequestedSessionIdFromURL() {
		return this.wrappedRequest.isRequestedSessionIdFromURL();
	}

	@SuppressWarnings(&quot;deprecation&quot;)
	@Override
	public boolean isRequestedSessionIdFromUrl() {
		return this.wrappedRequest.isRequestedSessionIdFromUrl();
	}

	@Override
	public boolean isRequestedSessionIdValid() {
		return this.wrappedRequest.isRequestedSessionIdValid();
	}

	@Override
	public boolean isUserInRole(String arg0) {
		return this.wrappedRequest.isUserInRole(arg0);
	}

}</pre>
<p>So the new methods being added here are &#8216;<em>removeParameter(String name)</em>&#8216; and &#8216;<em>setParameter(String name)</em>&#8216;, which do pretty much what their name implies.  If you are familiar with the standard &#8216;<em>removeAttribute(String name)</em>&#8216; and &#8216;<em>setAttribute(String name)</em>&#8216; methods, then you should feel right at home with these new additions.  They simply let you manipulate request parameters in a way that&#8217;s identical to how you can already manipulate request attributes.  </p>
<p>One minor deviation from the Servlet specification that is worth noting is that I have overridden &#8216;<em>getParameterValues(String name)</em>&#8216; such that it only returns the first value associated with a given parameter.  This means that if for some reason your webapp uses URL&#8217;s like &#8220;http://mysite.com/api?user=bob&#038;user=jane&#038;user=paul&#8221; then you will only see &#8220;bob&#8221; as a value for the &#8216;user&#8217; parameter.  In practice I have not ever come across a web application that intentionally relied on a single parameter name having multiple values associated with it, and if you are designing your web application in such a way then you should probably just stop and pick a less confusing pattern.  I see no value in a feature that allows a single parameter to have multiple values that you only get to see if you use a different API method to get them (&#8216;<em>getParameterValues</em>&#8216; instead of &#8216;<em>getParameter</em>&#8216;), and so I have removed this feature from the implementation.  If someone can come up with a solid justification for having such a feature, I will add it back in.</p>
<p>Also, left as an exercise is overriding &#8216;<em>getRequestURI()</em>&#8216;, &#8216;<em>getRequestURL()</em>&#8216;, and &#8216;<em>getQueryString()</em>&#8216; to return the correct values based upon the modified request state.  It&#8217;s fairly rare to have application code that depends upon the values of these calls, so in most cases you will not need to do this.</p>
<p>In any case, to make use of the OverridableHttpRequest class, you can do the following:</p>
<pre class="brush: java; title: ; notranslate">public class ExampleFilter implements Filter {
	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		//do initialization things here
	}

	@Override
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain filterChain) throws IOException, ServletException {

		HttpServletRequest httpReq = (HttpServletRequest) response;
		OverridableHttpRequest newRequest = new OverridableHttpRequest(httpReq);
     
		//do work and modify the request as desired
		newRequest.removeParameter(&quot;someBadXssParam&quot;);

		//pass the modified request on to the webapp, anyone downstream will see 
		//the modified state with no 'someBadXssParam' in it
		filterChain.doFilter(newRequest, response);
	}

	@Override
	public void destroy() {
		//do shutdown things here
	}
}</pre>
<p>Simple, but powerful.  I just wish the Servlet spec included this kind of functionality out of the box so that it wouldn&#8217;t be necessary to implement a complete HttpServletRequest wrapper just to add a couple of basic mutator methods.</p>
]]></content:encoded>
			<wfw:commentRss>https://codethink.no-ip.org/archives/634/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>[Objective-C + Cocoa] Screen Capture, Multiplexing, and More</title>
		<link>https://codethink.no-ip.org/archives/541</link>
		<comments>https://codethink.no-ip.org/archives/541#comments</comments>
		<pubDate>Mon, 28 Mar 2011 11:45:02 +0000</pubDate>
		<dc:creator><![CDATA[aroth]]></dc:creator>
				<category><![CDATA[coding]]></category>
		<category><![CDATA[objective-c]]></category>
		<category><![CDATA[cocoa]]></category>
		<category><![CDATA[hack]]></category>
		<category><![CDATA[objc]]></category>

		<guid isPermaLink="false">http://codethink.no-ip.org/wordpress/?p=541</guid>
		<description><![CDATA[It&#8217;s been a bit quiet on the coding-front lately, so I thought I&#8217;d share a small handful of various utilities that I&#8217;ve developed over the past few weeks. None of them are particularly revolutionary, but they can certainly prove useful &#8230; <a href="https://codethink.no-ip.org/archives/541">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>It&#8217;s been a bit quiet on the coding-front lately, so I thought I&#8217;d share a small handful of various utilities that I&#8217;ve developed over the past few weeks.  None of them are particularly revolutionary, but they can certainly prove useful in the right situations.  Anyways, in no particular order, I give you:</p>
<p><strong>ScreenCaptureView</strong></p>
<p>This bit of code allows you to easily capture the contents of any arbitrary UIView:</p>
<pre class="brush: cpp; title: ; notranslate">//  ScreenCaptureView.h
#import &lt;UIKit/UIKit.h&gt;

@interface ScreenCaptureView : UIView {
}

@property(retain) UIImage* currentScreen;
@property(assign) float frameRate;

@end


//  ScreenCaptureView.m
#import &quot;ScreenCaptureView.h&quot;
#import &lt;QuartzCore/QuartzCore.h&gt;

@implementation ScreenCaptureView

@synthesize currentScreen, frameRate;

- (id)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
        self.contentMode = UIViewContentModeRedraw;
        self.frameRate = 20.0f;//20 frames per seconds
    }
    return self;
}

- (void) drawRect:(CGRect)rect {
    CGContextRef context =  UIGraphicsGetCurrentContext();
    [self.layer renderInContext:context];
    CGImageRef cgImage = CGBitmapContextCreateImage(context);
    UIImage* background = [UIImage imageWithCGImage: cgImage];
    CGImageRelease(cgImage);
    self.currentScreen = background;
    
    [self performSelector:@selector(setNeedsDisplay) withObject:nil afterDelay:(1.0 / self.frameRate)];   //redraw at the specified framerate
}

- (void)dealloc {
    [super dealloc];
}
@end</pre>
<p>The &#8216;<em>ScreenCaptureView</em>&#8216; class automatically captures its current contents (including any nested subviews) to a UIImage which it exposes through the &#8216;<em>currentScreen</em>&#8216; property.  You can use this functionality to do things like generate screenshots of your application for use in help/tutorial (or promotional) content, and you can even pass the data as frames to an `<em>AVCaptureSession</em>` to create a live video of your app in action.</p>
<p><strong>Update:</strong>  An enhanced version of this class that includes the ability to record video is <a href="http://codethink.no-ip.org/wordpress/archives/673">now available</a>.</p>
<p><strong>MultiplexingDelegate</strong></p>
<p>For those rare cases when you want multiple delegate objects to be notified of a change/event in some object:</p>
<pre class="brush: cpp; title: ; notranslate">//  MultiplexingDelegate.h
#import &lt;Foundation/Foundation.h&gt;

@interface MultiplexingDelegate : NSObject {
    NSMutableArray* delegates;
}

- (void) addDelegate: (id) theDelegate;
- (void) removeDelegate: (id) theDelegate;
- (void) sendSelectorToDelegates: (SEL)selector withObject: (id)param1 andSecondObject: (id)param2
@end

//  MultiplexingDelegate.m
@implementation MultiplexingDelegate
- (id) init {
    if ((self = [super init])) {
        delegates = [[NSMutableArray alloc] initWithCapacity: 16];
    }
}

- (void) dealloc {
    [delegates release];
    [super dealloc]
}

- (void) addDelegate: (id) theDelegate {
    @synchronized(delegates) {
        if (theDelegate &amp;&amp; ! [delegates containsObject: theDelegate]) {
            [delegates addObject: theDelegate];
        }
    }
}

- (void) removeDelegate: (id) theDelegate {
    @synchronized(delegates) {
        if (theDelegate &amp;&amp; [delegates containsObject: theDelegate]) {
            [delegates removeObject: theDelegate];
        }
    }
}

- (void) sendSelectorToDelegates: (SEL)selector withObject: (id)param1 andSecondObject: (id)param2 {
    @synchronized(delegates) {
        for (id theDelegate in delegates) {
            if (param2) {
                [theDelegate performSelector:selector withObject:param1 withObject:param2];
            }
            else if (param1) {
                [theDelegate performSelector:selector withObject:param1];
            }
            else {
                [theDelegate performSelector:selector];
            }
        }
    }
}
@end</pre>
<p>The &#8216;<em>MultiplexingDelegate</em>` class provides a generic starting point for creating delegates that conform to various protocols and support the multiplexing of events to any number of attached listeners.  To use it you just need to create a new subclass of &#8216;<em>MultiplexingDelegate</em>&#8216; that implements whatever protocol you are interested in.  For instance, here is a partial example of a multiplexing UISearchBarDelegate implementation:</p>
<pre class="brush: cpp; title: ; notranslate">//  MultiplexingSearchBarDelegate.h
#import &lt;UIKit/UIKit.h&gt;
#import &quot;MultiplexingDelegate.h&quot;

@interface MultiplexingSearchBarDelegate : MultiplexingDelegate&lt;UISearchBarDelegate&gt; {
}
@end

//  MultiplexingSearchBarDelegate.m
@implementation MultiplexingSearchBarDelegate
//add UISearchBarDelegate methods here, following a pattern like this:
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
    [self sendSelectorToDelegates: @selector(searchBar:textDidChange:) withObject: searchBar andSecondObject: searchText];
}

//or alternately/equivalently, a pattern like this:
- (BOOL)searchBar:(UISearchBar *)searchBar shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
    @synchronized(delegates) {
        for (id&lt;UISearchBarDelegate&gt; theDelegate in delegates) {
            [theDelegate searchBar:searchBar shouldChangeTextInRange: range replacementText: text];
        }
    }
}
@end</pre>
<p>To use the &#8216;<em>MultiplexingSearchBarDelegate</em>&#8216; class you would create a single instance and add it as the delegate of your UISearchBar.  Then you just register every other object that you want to receive UISearchBar events with the &#8216;<em>MultiplexingSearchBarDelegate</em>&#8216; (by using the &#8216;<em>addDelegate:</em>&#8216; method), and they will all receive event notifications from the UISearchBar.  Simple, but powerful.</p>
<p><strong>NSString+JavaAPI</strong></p>
<p>There&#8217;s no getting around it, the standard NSString API just kind of sucks.  Wouldn&#8217;t it be great if NSString supported an API that was more like what Java provides through its String class?  Well now it can:</p>
<pre class="brush: cpp; title: ; notranslate">//  NSString+JavaAPI.h
#import &lt;Foundation/Foundation.h&gt;

@interface NSString (NSString_JavaAPI)
- (int) compareTo: (NSString*) comp;
- (int) compareToIgnoreCase: (NSString*) comp;
- (bool) contains: (NSString*) substring;
- (bool) endsWith: (NSString*) substring;
- (bool) startsWith: (NSString*) substring;
- (int) indexOf: (NSString*) substring;
- (int) indexOf:(NSString *)substring startingFrom: (int) index;
- (int) lastIndexOf: (NSString*) substring;
- (int) lastIndexOf:(NSString *)substring startingFrom: (int) index;
- (NSString*) substringFromIndex:(int)from toIndex: (int) to;
- (NSString*) trim;
- (NSArray*) split: (NSString*) token;
- (NSString*) replace: (NSString*) target withString: (NSString*) replacement;
- (NSArray*) split: (NSString*) token limit: (int) maxResults;
@end

//  NSString+JavaAPI.m
#import &quot;NSString+JavaAPI.h&quot;

@implementation NSString (NSString_JavaAPI)
- (int) compareTo: (NSString*) comp {
    NSComparisonResult result = [self compare:comp];
    if (result == NSOrderedSame) {
        return 0;
    }
    return result == NSOrderedAscending ? -1 : 1;
}

- (int) compareToIgnoreCase: (NSString*) comp {
    return [[self lowercaseString] compareTo:[comp lowercaseString]];
}

- (bool) contains: (NSString*) substring {
    NSRange range = [self rangeOfString:substring];
    return range.location != NSNotFound;
}

- (bool) endsWith: (NSString*) substring {
    NSRange range = [self rangeOfString:substring];
    return range.location == [self length] - [substring length];
}

- (bool) startsWith: (NSString*) substring {
    NSRange range = [self rangeOfString:substring];
    return range.location == 0;
}

- (int) indexOf: (NSString*) substring {
    NSRange range = [self rangeOfString:substring];
    return range.location == NSNotFound ? -1 : range.location;
}

- (int) indexOf:(NSString *)substring startingFrom: (int) index {
    NSString* test = [self substringFromIndex:index];
    return [test indexOf:substring];
}

- (int) lastIndexOf: (NSString*) substring {
    if (! [self contains:substring]) {
        return -1;
    }
    int matchIndex = 0;
    NSString* test = self;
    while ([test contains:substring]) {
        if (matchIndex &gt; 0) {
            matchIndex += [substring length];
        }
        matchIndex += [test indexOf:substring];
        test = [test substringFromIndex: [test indexOf:substring] + [substring length]];
    }
    
    return matchIndex;
}

- (int) lastIndexOf:(NSString *)substring startingFrom: (int) index {
    NSString* test = [self substringFromIndex:index];
    return [test lastIndexOf:substring];
}

- (NSString*) substringFromIndex:(int)from toIndex: (int) to {
    NSRange range;
    range.location = from;
    range.length = to - from;
    return [self substringWithRange: range];
}

- (NSString*) trim {
    return [self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}

- (NSArray*) split: (NSString*) token {
    return [self split:token limit:0];
}

- (NSArray*) split: (NSString*) token limit: (int) maxResults {
    NSMutableArray* result = [NSMutableArray arrayWithCapacity: 8];
    NSString* buffer = self;
    while ([buffer contains:token]) {
        if (maxResults &gt; 0 &amp;&amp; [result count] == maxResults - 1) {
            break;
        }
        int matchIndex = [buffer indexOf:token];
        NSString* nextPart = [buffer substringFromIndex:0 toIndex:matchIndex];
        buffer = [buffer substringFromIndex:matchIndex + [token length]];
        if (nextPart) {
            [result addObject:nextPart];
        }
    }
    if ([buffer length] &gt; 0) {
        [result addObject:buffer];
    }
    
    return result;
}

- (NSString*) replace: (NSString*) target withString: (NSString*) replacement {
    return [self stringByReplacingOccurrencesOfString:target withString:replacement];
}
@end</pre>
<p>Note that this isn&#8217;t the complete Java String API (and also that `<em>split()</em>` does not support regular-expressions as it does in Java).  It is just a subset consisting of the most useful Java API functions that do not have convenient analogs in the standard NSString API.  Still, it makes a lot of common string manipulations a lot more straightforward than they otherwise would be.</p>
]]></content:encoded>
			<wfw:commentRss>https://codethink.no-ip.org/archives/541/feed</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
		<item>
		<title>[JavaScript + CSS] Fun with Google Maps</title>
		<link>https://codethink.no-ip.org/archives/472</link>
		<comments>https://codethink.no-ip.org/archives/472#comments</comments>
		<pubDate>Fri, 11 Mar 2011 13:06:01 +0000</pubDate>
		<dc:creator><![CDATA[aroth]]></dc:creator>
				<category><![CDATA[coding]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[hack]]></category>

		<guid isPermaLink="false">http://codethink.no-ip.org/wordpress/?p=472</guid>
		<description><![CDATA[Here are a couple of quick Google Maps hacks that I came up with quite awhile ago; several years ago, in fact. While not hugely useful or profound, they do expose some fairly large holes in the Google Maps API. &#8230; <a href="https://codethink.no-ip.org/archives/472">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Here are a couple of quick Google Maps hacks that I came up with quite awhile ago; several years ago, in fact.  While not hugely useful or profound, they do expose some fairly large holes in the Google Maps API.  Holes that I would have expected a company like Google to have patched up by now.  </p>
<p>First, let&#8217;s say that for whatever reason you need to remove the &#8220;Powered by Google&#8221; logo and the other copyright and similar boilerplate that normally appears along the bottom of the map.  Why would you want to do this?  Perhaps because you are displaying your map inside of a small area of the page where space is constrained to the point that the logo and other things are adding too much noise.  Or perhaps because you feel (quite justifiably) that Google Maps have become iconic to the point that nobody needs to see a &#8220;Powered by Google&#8221; logo in the corner to know that the map is being powered by Google.  </p>
<p>Whatever your reason for wanting to unclutter the map&#8217;s footer section, the task can be accomplished using a smidgen of CSS:</p>
<pre class="brush: css; title: ; notranslate">		.terms-of-use-link {
		    display: none;
		}

		#myMapContainerId div span {
			display: none;
		}</pre>
<p>&#8230;and a handful of JavaScript:</p>
<pre class="brush: jscript; title: ; notranslate">			//call this after setting up your GMap2 instance
			window.unclutter = function() {
				var executed = false;
				var images = document.getElementsByTagName('img');
				for (var index = 0; index &lt; images.length; index++) {
					var node = images[index];
					if (node.src &amp;&amp; node.src.indexOf(&quot;mapfiles/poweredby.png&quot;) &gt; 0) {
						node.style.display = 'none';
						executed = true;
					}
				}

				if (! executed) {
					setTimeout(window.unclutter, 250);
				}
			};</pre>
<p>It&#8217;s pretty straightforward, really.  The CSS gets rid of the &#8220;Terms of Use&#8221; link, as well as the spans that are used to display copyright text (note that you should replace the &#8216;<em>myMapContainerId</em>&#8216; with whatever your actual map div-id is).  The JavaScript is used to get rid of the &#8220;Powered by Google&#8221; logo, which is added to the map after it loads.  To use this code, you just need to call &#8216;<em>unclutter()</em>&#8216; after setting up your Google Map instance.</p>
<p>Of course, doing this is a blatant violation of the Google Maps Terms of Service.  You know, the terms Google made you agree to when you generated your API key.  Whether or not there is any merit in having Terms of Service mandate things which do nothing whatsoever to benefit end users such as the display of logos and copyright gibberish is a topic for another day.  The topic for today is, if Google Maps can be used without an API key, and hence without agreeing to the Terms of Service, what does it matter what the terms are anyways?  </p>
<p>That&#8217;s right, the Google Maps API can be used, at least for basic tasks, completely without an API key.  It&#8217;s quite simple really, just a tiny bit more JavaScript:</p>
<pre class="brush: jscript; title: ; notranslate">			//be sure to do this *before* you source in the Google Maps javascript
			window._alert = window.alert;
			window.alert = function() {return;};</pre>
<p>&#8230;and then you can include the Google Maps JavaScript without specifying an API key, like so:</p>
<pre class="brush: xml; title: ; notranslate">&lt;script src=&quot;http://maps.google.com/maps?file=api&amp;amp;v=2&amp;amp;sensor=true&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;</pre>
<p>The added JavaScript simply moves the browser&#8217;s built-in &#8216;<em>alert()</em>&#8216; function to &#8216;<em>_alert()</em>&#8216; so that the map can&#8217;t use it to display a message complaining about the missing API key.  For whatever reason, apart from this alert message Google does nothing to prevent their API from being used without a valid key.  So by simply suppressing the error message you can get a fully functional Google map without registering for a key or agreeing to the Terms of Service.</p>
<p>Put all of this together and you can get an anonymous, unbranded, uncluttered map the works just as well as the original version.  The source code (verified in current versions of IE, Firefox, and Chrome) might look something like this:</p>
<pre class="brush: xml; title: ; notranslate">&lt;html&gt;
	&lt;head&gt;
		&lt;title&gt;Google Maps API Example Hack&lt;/title&gt;
		&lt;style&gt;
			.terms-of-use-link {
		    		display: none;
			}

			#myMapContainerId div span {
			     display: none;
			}
		&lt;/style&gt;
		&lt;script type=&quot;text/javascript&quot;&gt;
			window._alert = window.alert;
			window.alert = function() {return;};

			window.setupMap = function() {
				window.map = new GMap2(document.getElementById(&quot;myMapContainerId&quot;));
				map.setCenter(new GLatLng(37.4419, -122.1419), 13);
				map.addControl(new GLargeMapControl3D());
				map.addControl(new GMapTypeControl());
			};

			window.unclutter = function() {
				var executed = false;
				var images = document.getElementsByTagName('img');
				for (var index = 0; index &lt; images.length; index++) {
					var node = images[index];
					if (node.src &amp;&amp; node.src.indexOf(&quot;mapfiles/poweredby.png&quot;) &gt; 0) {
						node.style.display = 'none';
						executed = true;
					}
				}

				if (! executed) {
					setTimeout(window.unclutter, 250);
				}
			};

			window.onload = function() {setupMap(); unclutter();};
		&lt;/script&gt;
		&lt;script src=&quot;http://maps.google.com/maps?file=api&amp;amp;v=2&amp;amp;sensor=true&amp;amp;&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
	&lt;/head&gt;
	&lt;body&gt;
		Note the lack of branding/logos, terms of use links, and copyright footer text in the map below.&lt;br /&gt;
		Also note the lack of any Google Maps API key in the document source.&lt;br /&gt;
		And the lack of any annoying &lt;a href=&quot;#&quot; onclick=&quot;_alert('I can still create alerts, but the Google Map can\'t.'); return false;&quot;&gt;alert&lt;/a&gt; popups complaining about the API key.&lt;br /&gt;&lt;br /&gt;
		&lt;div id=&quot;myMapContainerId&quot; style=&quot;width: 600px; height: 400px;&quot;&gt;&lt;/div&gt;
	&lt;/body&gt;
&lt;/html&gt;</pre>
<p>&#8230;which gives you a page like <a href="http://codethink.no-ip.org/mapHacks.html" target="_blank">this one</a>.  It&#8217;s enough to make one wonder why anyone would bother signing up for a Google Maps API key the proper way, when the entire thing can be subverted so easily.</p>
]]></content:encoded>
			<wfw:commentRss>https://codethink.no-ip.org/archives/472/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>[Cocoa + iPhone] Avoiding &#8216;_handleMemoryWarning:&#8217; Crashes</title>
		<link>https://codethink.no-ip.org/archives/455</link>
		<comments>https://codethink.no-ip.org/archives/455#comments</comments>
		<pubDate>Sat, 05 Mar 2011 02:28:42 +0000</pubDate>
		<dc:creator><![CDATA[aroth]]></dc:creator>
				<category><![CDATA[coding]]></category>
		<category><![CDATA[objective-c]]></category>
		<category><![CDATA[hack]]></category>
		<category><![CDATA[objc]]></category>

		<guid isPermaLink="false">http://codethink.no-ip.org/wordpress/?p=455</guid>
		<description><![CDATA[Spend enough time developing iPhone applications (particularly if you go to the trouble of collecting crash logs from your apps), and eventually you are bound to come across something like the following: This error occurs most frequently when suspending an &#8230; <a href="https://codethink.no-ip.org/archives/455">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Spend enough time developing iPhone applications (particularly if you go to the trouble of collecting crash logs from your apps), and eventually you are bound to come across something like the following:</p>
<pre class="brush: plain; title: ; notranslate">2011-03-04 14:17:48.872 myApp[15129:307] -[UIImageView _handleMemoryWarning:]: unrecognized selector sent to instance 0x2b2060
[Switching to process 11523 thread 0x0]
2011-03-04 14:17:57.034 myApp[15129:307] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIImageView _handleMemoryWarning:]: unrecognized selector sent to instance 0x2b2060'
*** Call stack at first throw:
(
	0   CoreFoundation                      0x3759dc7b __exceptionPreprocess + 114
	1   libobjc.A.dylib                     0x32d9bee8 objc_exception_throw + 40
	2   CoreFoundation                      0x3759f3e3 -[NSObject(NSObject) doesNotRecognizeSelector:] + 98
	3   CoreFoundation                      0x37544467 ___forwarding___ + 506
	4   CoreFoundation                      0x37544220 _CF_forwarding_prep_0 + 48
	5   Foundation                          0x351663b5 _nsnote_callback + 156
	6   CoreFoundation                      0x37520971 __CFXNotificationPost_old + 396
	7   CoreFoundation                      0x37520611 _CFXNotificationPostNotification + 128
	8   Foundation                          0x351556a3 -[NSNotificationCenter postNotificationName:object:userInfo:] + 70
	9   Foundation                          0x3515edbd -[NSNotificationCenter postNotificationName:object:] + 20
	10  UIKit                               0x35a32354 -[UIApplication _performMemoryWarning] + 68
	11  UIKit                               0x35a33450 -[UIApplication _receivedMemoryNotification] + 184
	12  UIKit                               0x35a2ef24 _memoryStatusChanged + 64
	13  CoreFoundation                      0x37552333 __CFNotificationCenterDarwinCallBack + 26
	14  CoreFoundation                      0x37537e37 __CFMachPortPerform + 218
	15  CoreFoundation                      0x3752f5cb __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 28
	16  CoreFoundation                      0x3752f589 __CFRunLoopDoSource1 + 164
	17  CoreFoundation                      0x37521835 __CFRunLoopRun + 580
	18  CoreFoundation                      0x3752150b CFRunLoopRunSpecific + 226
	19  CoreFoundation                      0x37521419 CFRunLoopRunInMode + 60
	20  GraphicsServices                    0x33e76d24 GSEventRunModal + 196
	21  UIKit                               0x3591d57c -[UIApplication _run] + 588
	22  UIKit                               0x3591a558 UIApplicationMain + 972
	23  myApp                             0x00002649 main + 96
	24  myApp                             0x000025b0 start + 52
)
terminate called after throwing an instance of 'NSException'</pre>
<p>This error occurs most frequently when suspending an app to the background, but it can also happen randomly at other times as well.  Of course, the problem here should be obvious; the crash happens entirely outside of my application code.  After the call to &#8216;<em>main()</em>&#8216; the stack-trace that leads to the crash lies entirely within framework code.  The problem appears to be that some CoreFoundation class is attempting to invoke a &#8216;<em>_handleMemoryWarning:</em>&#8216; selector on objects that do not support it.  </p>
<p>So how to prevent a crash that happens completely outside of your application code?  You might say &#8220;use less memory&#8221;, but that is not a reliable answer here.  The &#8216;<em>_performMemoryWarning</em>&#8216; selector may still be invoked no matter how streamlined your memory usage is.  The answer, or at least the only answer I&#8217;ve found that works reliably, is to use a custom UIApplication subclass and excise the functionality that causes this error, like so:</p>
<pre class="brush: cpp; title: ; notranslate">//
//  SafeUIApplication.h
//  myApp
//
#import &lt;Foundation/Foundation.h&gt;

@interface SafeUIApplication : UIApplication {
}

@end


//
//  SafeUIApplication.m
//  myApp
//
#import &quot;SafeUIApplication.h&quot;

@implementation SafeUIApplication

//these selectors cause crashes in random Foundation classes when the default implementation is called, so instead of crashing our app 
//we ignore these messages, hold on to the memory that has already been allocated to us, and let some other less-clever app crash instead
- (void) _performMemoryWarning {
    NSLog(@&quot;Received a '_performMemoryWarning' call, consider using less memory...&quot;);
    return;
}
- (void) _receivedMemoryNotification {
    NSLog(@&quot;Received a '_receivedMemoryNotification' call, consider using less memory...&quot;);
    return;
}

@end</pre>
<p>Now before the purists and the pedants go jumping down my throat:  Yes, this is a hack.  Yes, it disables built-in memory-management functionality.  Yes, it can mask legitimate problems if your app does in fact have a memory leak (or if it just makes inefficient use of memory).  But having built-in memory-management functionality that crashes the app when called is completely unacceptable in my book, and so disabling it is fair game.  Further, even with this bit of code disabled, the application will still continue to receive low memory warnings (&#8216;<em>didReceiveMemoryWarning</em>&#8216; calls) as normal.  Hanging on to memory that is already allocated to the app cannot cause the app to crash or behave incorrectly, it just means that less memory is available for other apps that are also running.  That seems fair enough to me, at least so long as the default implementation of these methods causes apps to crash.</p>
<p>Anyways, once you&#8217;ve added the SafeUIApplication class to your project, using it is as simple as modifying your application&#8217;s &#8216;main.m&#8217; file like so:</p>
<pre class="brush: cpp; title: ; notranslate">//
//  main.m
//  myApp
//
#import &lt;UIKit/UIKit.h&gt;

int main(int argc, char *argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    int retVal = UIApplicationMain(argc, argv, @&quot;SafeUIApplication&quot;, @&quot;MyAppDelegateClassName&quot;);
    [pool release];
    return retVal;
}</pre>
<p>Just specify the SafeUIApplication classname and your UIApplicationDelegate classname, and you no longer need to worry about obscure &#8216;<em>_handleMemoryWarning:</em>&#8216; crashes.  As noted above, be aware that this will do little to nothing to help applications that have legitimate memory usage issues.  But if you are confident that your application&#8217;s memory usage is correct and you are still experiencing crashes like the one shown above then this little hack will go a very long way towards keeping your application running and stable.</p>
]]></content:encoded>
			<wfw:commentRss>https://codethink.no-ip.org/archives/455/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>[Cocoa + iPhone] UITableViewCell:  It&#8217;s Broken!</title>
		<link>https://codethink.no-ip.org/archives/367</link>
		<comments>https://codethink.no-ip.org/archives/367#comments</comments>
		<pubDate>Thu, 10 Feb 2011 13:27:59 +0000</pubDate>
		<dc:creator><![CDATA[aroth]]></dc:creator>
				<category><![CDATA[coding]]></category>
		<category><![CDATA[objective-c]]></category>
		<category><![CDATA[hack]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[objc]]></category>

		<guid isPermaLink="false">http://codethink.no-ip.org/wordpress/?p=367</guid>
		<description><![CDATA[I present for your consideration the following screenshot: It shows a basic table-view, in which each cell has been assigned the same image (using its built-in &#8216;imageView&#8216; property). The source image is 20 pixels square, and the imageView&#8217;s &#8216;contentMode&#8216; property &#8230; <a href="https://codethink.no-ip.org/archives/367">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>I present for your consideration the following screenshot:</p>
<p><a href="http://codethink.no-ip.org/wordpress/wp-content/uploads/2011/02/Screen-shot-2011-02-10-at-12.31.37-AM.png" rel="lightbox[367]"><img src="http://codethink.no-ip.org/wordpress/wp-content/uploads/2011/02/Screen-shot-2011-02-10-at-12.31.37-AM.png" alt="UITableViewCell is broken!" title="UITableViewCell is broken!" width="360" height="711" class="aligncenter size-full wp-image-371" /></a></p>
<p>It shows a basic table-view, in which each cell has been assigned the same image (using its built-in &#8216;<em>imageView</em>&#8216; property).  The source image is 20 pixels square, and the imageView&#8217;s &#8216;<em>contentMode</em>&#8216; property has not been changed (not that changing it makes any difference). The image for each row is also being scaled to 50% and rendered at the orientation stated in the cell text.  The code for the table controller is as follows:</p>
<pre class="brush: cpp; title: ; notranslate">#import &quot;UITableViewTestViewController.h&quot;

static NSString* rowNames[8] = {@&quot;UIImageOrientationUp&quot;, @&quot;UIImageOrientationDown&quot;, @&quot;UIImageOrientationLeft&quot;, @&quot;UIImageOrientationRight&quot;, 
                                @&quot;UIImageOrientationUpMirrored&quot;, @&quot;UIImageOrientationDownMirrored&quot;, @&quot;UIImageOrientationLeftMirrored&quot;, 
                                @&quot;UIImageOrientationRightMirrored&quot;};

#define IMAGE_NAME @&quot;testImage.png&quot;

@implementation UITableViewTestViewController

- (void)dealloc {
    [super dealloc];
}

- (void)didReceiveMemoryWarning {
    // Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];
}

#pragma mark - View lifecycle
- (int) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return 8;  //number of elements in the enumeration
}

- (int) numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

- (UITableViewCell*) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString* cellIdentifier = @&quot;TestCell&quot;;
    
    //return a basic cell with the icon in it and some text
    UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:@&quot;StationCell&quot;];
    if (cell == nil) {
        //init cell
        cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:cellIdentifier] autorelease];
    }
    
    cell.accessoryType = UITableViewCellAccessoryNone;
    cell.textLabel.text = rowNames[indexPath.row];          //enum starts from 0, so indexPath.row matches the orientation that we are going to apply
    cell.textLabel.font = [cell.textLabel.font fontWithSize:12.0];
    cell.textLabel.textColor = [UIColor darkGrayColor];
    cell.imageView.image =  [UIImage imageWithCGImage:[UIImage imageNamed:IMAGE_NAME].CGImage scale:0.5 orientation:indexPath.row];  //the scale operation will be ignored for UIImageOrientationUp; because something is broken
    
    return cell;
}

- (void) tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
    //it makes no difference if we set the image here
    //cell.imageView.image =  [UIImage imageWithCGImage:[UIImage imageNamed:IMAGE_NAME].CGImage scale:0.5 orientation:indexPath.row];
}
@end</pre>
<p>It&#8217;s not doing anything all that special, but as you can see in the screenshot the image in the first cell is rendered differently than all the others.  More specifically, it is being stretched to the full size of its container so that it just looks kind of sad, and no amount of programmatic scale operations will fix it.  </p>
<p>This can be one of the most maddening aspects about working with table-cells and images.  If you want an image that is slightly smaller than its container in the table-cell, or that is centered away from the top/side, then the only consistent way to do so is to create a custom table-cell.  And while it is not difficult to create a custom table-cell that implements the desired behavior, it needlessly clutters the source-tree with code that replicates functionality that Apple is supposed to be providing out of the box.</p>
<p>The problem, as exposed by this example code, is that when an image is scaled using UIImageOrientationUp (which is what most developers would use, given that they generally store their images in the orientation they want them displayed at) the UITableViewCell completely ignores the scaling operation.  I can only speculate as to the reason for this odd behavior, because at the very least I would expect the output to be the same no matter what UIImageOrientation is used (i.e. I would think that scaling would either consistently not work or consistently work, but this is manifestly not the case).</p>
<p>In any case, this behavior is very clearly a bug, and a particularly inconvenient one at that.  But it does expose a potential workaround that generates less source-clutter than creating a custom table-cell implementation every time you want to have cell images that actually work.  Just store your images upside-down (or preprocess them so that they are upside-down prior to adding to the table) and then invert them back to the proper orientation when you scale them to the size you want for your table.  </p>
<p>It&#8217;s dodgy as all hell to do it that way, but still arguably better than reimplementing functionality that Apple is supposed to be providing out of the box.</p>
<p>Project source code is available here:  <a href="http://codethink.no-ip.org/UITableViewTest.zip">http://codethink.no-ip.org/UITableViewTest.zip</a></p>
]]></content:encoded>
			<wfw:commentRss>https://codethink.no-ip.org/archives/367/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[Cocoa + iPhone] Unraveling Apple&#8217;s Pagecurl</title>
		<link>https://codethink.no-ip.org/archives/320</link>
		<comments>https://codethink.no-ip.org/archives/320#comments</comments>
		<pubDate>Wed, 09 Feb 2011 13:17:04 +0000</pubDate>
		<dc:creator><![CDATA[aroth]]></dc:creator>
				<category><![CDATA[coding]]></category>
		<category><![CDATA[objective-c]]></category>
		<category><![CDATA[hack]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[objc]]></category>

		<guid isPermaLink="false">http://codethink.no-ip.org/wordpress/?p=320</guid>
		<description><![CDATA[First off, I encourage anyone that&#8217;s unfamiliar of this topic to read through this short but very sweet blog post on the subject (and to take a quick look at his sample code). We&#8217;ll be picking up where Steven left &#8230; <a href="https://codethink.no-ip.org/archives/320">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>First off, I encourage anyone that&#8217;s unfamiliar of this topic to read through this <a href="http://blog.steventroughtonsmith.com/2010/02/apples-ibooks-dynamic-page-curl.html" target="_blank">short but very sweet blog post</a> on the subject (and to take a quick look at his sample code).  We&#8217;ll be picking up where Steven left off.</p>
<p>In any case, to summarize the current situation; there exists a private and undocumented API in the iPhone SDK which Apple uses to great effect in their iBook application.  The way to interface with this private API has been discovered and even <a href="http://www.iphonedevwiki.net/index.php?title=CAFilter" target="_blank">fairly well documented</a>.  Using the private API is pretty straightforward but for one small problem:  if you use the private API in your application then Apple will reject your app.  For whatever non-specified reason (probably to keep potential iBook competitors in check), Apple does not want to open up their private API to developers or to play nice with developers who bend the rules and use the private API.  </p>
<p>So our goal is clear.  If Apple isn&#8217;t going to play nice and open the API up to developers, then perhaps we can do some digging to figure out how Apple&#8217;s implementation actually works and create our own implementation that does the same thing.  It&#8217;s a pretty standard exercise in reverse-engineering, really.  The core of the private page-curl API is used like so:</p>
<pre class="brush: cpp; title: ; notranslate">		filter = [[CAFilter filterWithType:kCAFilterPageCurl] retain];
		[filter setDefaults];
		[filter setValue:[NSNumber numberWithFloat:((NSUInteger)fingerDelta)/100.0] forKey:@&quot;inputTime&quot;];
		
		CGFloat _angleRad = angleBetweenCGPoints(currentPos, lastPos);
		CGFloat _angle = _angleRad*180/M_PI ; // I'm far more comfortable with using degrees <img src="https://codethink.no-ip.org/wp-includes/images/smilies/icon_wink.gif" alt=";-)" class="wp-smiley" />
					
		if (_angle &lt; 180 &amp;&amp; _angle &gt; 120) {// here I've limited the results to the right-hand side of the paper. I'm sure there's a better way to do this
			if (fingerVector.y &gt; 0)
				[filter setValue:[NSNumber numberWithFloat:_angleRad] forKey:@&quot;inputAngle&quot;];
			else
				[filter setValue:[NSNumber numberWithFloat:-_angleRad] forKey:@&quot;inputAngle&quot;];

			_internalView.layer.filters = [NSArray arrayWithObject:filter];
		}</pre>
<p>This is an excerpt straight out of Steven Troughton-Smith&#8217;s example.  The example includes additional code related to tracking touch positions and interpolating the angle and distance between them, but this is really the core of the private API right here.  All of the heavy-lifting is handled by the CAFilter class (private), which has a type of &#8216;<em>kCAFilterPageCurl</em>&#8216; (private constant, just the string <em>@&#8221;pageCurl&#8221;</em>, other filter types also exist), and which takes just a small number of input parameters (&#8216;<em>inputTime</em>&#8216; and &#8216;<em>inputAngle</em>&#8216;) and then works its magic behind the scenes.</p>
<p>So given that CAFilter seems to be doing pretty much all the work, it would follow that by constructing our own class that exposes the same interface as CAFilter we can supplant the private-API class with one of our own making (ah, the joys of reflection and weak-typing), thus interfacing with the underlying platform without breaking any of the rules.  But what exactly is a CAFilter?  Is it as onerous as a UIView with its hundreds of methods and properties?  Does it extend another obscure private-API class that will also need to be reverse-engineered?  Well thanks to the &#8216;<em><a href="http://codethink.no-ip.org/wordpress/archives/236">printObject:toDepth:</a></em>&#8216; routine discussed in a previous post we can see that a CAFilter is exactly:</p>
<pre class="brush: cpp; title: ; notranslate">@interface CAFilter : NSObject {
	unsigned int _type;
	NSString* _name;
	unsigned int _flags;
	void* _attr;
	void* _cache;
}

//Constructors
- (id) initWithType:  (NSString*) arg0;
- (id) initWithName:  (NSString*) arg0;

//NSCoding
- (NSObject*) initWithCoder:  (NSCoder*) arg0;
- (void) encodeWithCoder:  (NSCoder*) arg0;

//NSKeyValueCoding
- (void) setValue: (id) arg0 forKey: (NSString*) arg1;
- (id) valueForKey:  (NSString*) arg0;

//NSCopying and NSMutableCopying
- (NSObject*) mutableCopyWithZone:  (NSZone*) arg0;
- (NSObject*) copyWithZone:  (NSZone*) arg0;

//interface methods
- (void) setDefaults;
- (bool) isEnabled;
- (struct UnknownAtomic*) CA_copyRenderValue;

//garbage collection (doesn't need to be declared here)
- (void) dealloc;

//property accessors (don't need to be declared here)
- (bool) enabled;
- (void) setEnabled:  (bool) arg0;
- (bool) cachesInputImage;
- (void) setCachesInputImage:  (bool) arg0;
- (NSString*) name;
- (void) setName:  (NSString*) arg0;
- (NSObject*) type;

//properties
@property(nonatomic, readonly) NSString* type;
@property(nonatomic, retain) NSString* name;
@property(nonatomic) bool enabled;
@property(nonatomic) bool cachesInputImage;

@end</pre>
<p>Nineteen methods and a handful of fields.  Not bad, not bad at all, particularly when many of the methods are simply implementing various publicly-documented protocols such as NSCoding, NSCopying, and NSKeyValueCoding.  As an added bonus, the superclass of CAFilter is NSObject, so the problem has now been reduced to the implementation of a single unknown class (which may still be a Herculean task, but at least now there are clearly-defined boundaries).  </p>
<p>But the above code includes some methods that do not need to be part of the publicly declared interface.  Let&#8217;s clean it up, rename it so that it doesn&#8217;t conflict with the existing private-API class, and add the proper definition of the &#8216;<em>&#8230;Atomic</em>&#8216; struct:</p>
<pre class="brush: cpp; title: ; notranslate">#import &lt;Foundation/Foundation.h&gt;

struct RenderValueResult { 
	int (**x1)(); 
	struct MyAtomic { 
		struct { 
			NSInteger x; 
		} _v; 
	} x2; 
} *_filterResult;

@interface MyCAFilter : NSObject&lt;NSCoding, NSCopying, NSMutableCopying&gt; {
	unsigned int _type;
	NSString* _name;
	unsigned int _flags;
	void* _attr;
	void* _cache;
}

//Constructors
- (id) initWithType:  (NSString*) arg0;
- (id) initWithName:  (NSString*) arg0;

//NSKeyValueCoding
- (void) setValue: (id) arg0 forKey: (NSString*) arg1;
- (id) valueForKey:  (NSString*) arg0;

//interface methods
- (void) setDefaults;
- (bool) isEnabled;
- (struct RenderValueResult*) CA_copyRenderValue;

//properties
@property(nonatomic, readonly) NSString* type;
@property(nonatomic, retain) NSString* name;
@property(nonatomic) bool enabled;
@property(nonatomic) bool cachesInputImage;

@end</pre>
<p>Looking better already.  That &#8216;<em>RenderValueResult</em>&#8216; struct will prove to be a nasty one, but more on that later.</p>
<p>Now that we know the interface, and before we go flying off randomly trying to replicate functionality that we still don&#8217;t fully understand, let&#8217;s take a simpler step.  Let&#8217;s create a simple class that exposes the CAFilter interface, wraps an actual CAFilter instance, and logs each method call, parameters, and result, like so:</p>
<pre class="brush: cpp; title: ; notranslate">//MyCAFilter.h (modified to include 'delegate' field)
#import &lt;Foundation/Foundation.h&gt;

struct RenderValueResult {
    int (**x1)();
    struct MyAtomic {
        struct {
            NSInteger x;
        } _v;
    } x2;
} *_renderValueResult;

@class CAFilter;  //private-API

@interface MyCAFilter : NSObject&lt;NSCoding, NSCopying, NSMutableCopying&gt; {
    unsigned int _type;
    NSString* _name;
    unsigned int _flags;
    void* _attr;
    void* _cache;
    
    CAFilter* delegate;  //private-API
}

//Constructors
- (id) initWithType:  (NSString*) arg0;
- (id) initWithName:  (NSString*) arg0;

//NSKeyValueCoding
- (void) setValue: (id) arg0 forKey: (NSString*) arg1;
- (id) valueForKey:  (NSString*) arg0;

//interface methods
- (void) setDefaults;
- (bool) isEnabled;
- (struct RenderValueResult*) CA_copyRenderValue;

//properties
@property(nonatomic, readonly) NSString* type;
@property(nonatomic, retain) NSString* name;
@property(nonatomic) bool enabled;
@property(nonatomic) bool cachesInputImage;

@end

//MyCAFilter.m
#import &quot;MyCAFilter.h&quot;

@implementation MyCAFilter

@dynamic name, cachesInputImage, type, enabled;

- (id) initWithType: (NSString*) theType {
	NSLog(@&quot;initWithType: type='%@'&quot;, theType);
    if ((self = [super init])) {
        delegate = [[CAFilter alloc] initWithType: theType];    //TODO:  remove delegate
    }
	return self;
}

- (id) initWithName: (NSString*) theName {
	NSLog(@&quot;initWithName: name='%@'&quot;, theName);
    if ((self = [super init])) {
        delegate = [[CAFilter alloc] initWithName: theName];    //TODO:  remove delegate
    }
	return self;
}

- (id) initWithCoder: (NSCoder*) coder {
	NSLog(@&quot;initWithCoder: coder=%@&quot;, coder);
	if ((self = [super init])) {
        delegate = [[CAFilter alloc] initWithCoder: coder];     //TODO:  remove delegate
    }
    return self;
}

- (void) setDefaults {
	NSLog(@&quot;setDefaults&quot;);
	[delegate setDefaults];  //TODO:  remove delegate
}

- (void) encodeWithCoder: (NSCoder*) encoder {
	NSLog(@&quot;encodeWithCoder:  coder=%@&quot;, encoder);
	[delegate encodeWithCoder:encoder];  //TODO:  remove delegate
}

- (id) mutableCopyWithZone: (NSZone*) zone {
    id result = [delegate mutableCopyWithZone:zone];   //TODO:  remove delegate
	NSLog(@&quot;mutableCopyWithZone: zone=%@; result=%@&quot;, zone);
	return result;
}

- (id) copyWithZone: (NSZone*) zone {
    id result = [delegate copyWithZone:zone];  //TODO:  remove delegate
	NSLog(@&quot;copyWithZone:  zone=%@; result=%@&quot;, zone, result);
	return result;
}

- (void) setValue: (id) value forKey: (NSString*) key {
	NSLog(@&quot;setValue:  key=%@, value=%@&quot;, key, value);
	[delegate setValue:value forKey:key];	//TODO:  remove delegate
}

- (id) valueForKey:(id) key {
    id result = [delegate valueForKey:key];  //TODO:  remove delegate
	NSLog(@&quot;valueForKey:  key=%@; result=%@&quot;, key, result);
	return result;
}

- (bool) isEnabled {
    bool result = [delegate isEnabled]; //TODO:  remove delegate
	NSLog(@&quot;isEnabled; result=%d&quot;, result);
	return result; 
}

- (void) dealloc {
	NSLog(@&quot;dealloc&quot;);
	[delegate release];		//TODO:  remove delegate
	[super dealloc];
}

- (bool) enabled {
    bool result = [delegate enabled];		//TODO:  remove delegate
	NSLog(@&quot;enabled; result=%d&quot;, result);
	return result;
}
- (void) setEnabled: (bool) val {
	NSLog(@&quot;setEnabled: value=%d&quot;, val);
	[delegate setEnabled:val];		//TODO:  remove delegate
}

- (void) setCachesInputImage: (bool) val {
	NSLog(@&quot;setCachesInputImage: val=%d&quot;, val);
	[delegate setCachesInputImage:val];		//TODO:  remove delegate
}
- (bool) cachesInputImage {
    bool result = [delegate cachesInputImage];		//TODO:  remove delegate
	NSLog(@&quot;cachesInputImage; result=%d&quot;, result);
	return result;
}

- (id) name {
    id result = [delegate name];		//TODO:  remove delegate
	NSLog(@&quot;name; result=%@&quot;, result);
	return result;
}

- (void) setName: (NSString*) name {
	NSLog(@&quot;setName: name='%@'&quot;, name);
	[delegate setName: name];		//TODO:  remove delegate
}

- (NSString*) type {
    NSString* result = [delegate type];		//TODO:  remove delegate
	NSLog(@&quot;type; result=%@&quot;, result);
	return result;
}

- (struct RenderValueResult*) CA_copyRenderValue {
	struct RenderValueResult* result = [delegate CA_copyRenderValue];	//TODO:  remove delegate
    NSLog(@&quot;CA_copyRenderValue; result=0x%08X, result.x1=0x%08X, result.x2=%d&quot;, result, result-&gt;x1, result-&gt;x2);
	return result;
}

@end</pre>
<p>Using this class is a simple matter of editing &#8216;<em>ReadPdfView.m</em>&#8216; (working with Steven&#8217;s example project) to replace both instances of &#8216;<em>[[CAFilter filterWithType:kCAFilterPageCurl] retain];</em>&#8216; with &#8216;<em>[[MyCAFilter alloc] initWithType: @&#8221;pageCurl&#8221;];</em>&#8216;.  Note that it is also now safe to remove the &#8216;<em>@class CAFilter;</em>&#8216; and &#8216;<em>extern NSString *kCAFilterPageCurl;</em>&#8216; lines from this class.</p>
<p>Now obviously this still won&#8217;t fly with Apple, as it continues to use the private-API CAFilter class.  But consider what we&#8217;ve accomplished; we&#8217;ve now inserted our own custom object into the rendering pipeline, and the core-animation framework is none-the-wiser.  If we can now figure out how to get the same results without internally using the CAFilter instance, we will have cracked the page-curl animation.</p>
<p>Moving along, if we run this code through a complete page-curl animation, we see a very simple pattern emerge:</p>
<pre class="brush: plain; title: ; notranslate">2011-02-09 00:59:11.694 PageCurlDemo[5501:207] initWithType: type='pageCurl'
2011-02-09 00:59:11.707 PageCurlDemo[5501:207] setDefaults
2011-02-09 00:59:11.711 PageCurlDemo[5501:207] setValue:  key=inputTime, value=0
2011-02-09 00:59:11.716 PageCurlDemo[5501:207] setValue:  key=inputAngle, value=-3.141593
2011-02-09 00:59:11.734 PageCurlDemo[5501:207] CA_copyRenderValue; result=0x04AF09E0, result.x1=0x00D96448, result.x2=65538
2011-02-09 00:59:11.767 PageCurlDemo[5501:207] valueForKey:  key=inputTime; result=0
2011-02-09 00:59:11.808 PageCurlDemo[5501:207] dealloc</pre>
<p>This sequence of calls is repeated a number of times as the animation runs.  None of the other methods that exist on the object are called.  Every single one of these calls with the exception of &#8216;<em>CA_copyRenderValue</em>&#8216; originates in the example code; so now our task is constrained to the implementation of a single unknown method.  But what a method it is.  &#8216;<em>CA_copyRenderValue</em>&#8216; returns an instance of a fairly obtuse structure that has the following definition:</p>
<pre class="brush: cpp; title: ; notranslate">struct RenderValueResult { 
	int (**x1)(); 
	struct MyAtomic { 
		struct { 
			NSInteger x; 
		} _v; 
	} x2; 
} *_renderValueResult;</pre>
<p>I&#8217;ve changed the name of the structure and its nested structure to avoid any issues with name collisions, but since the order and type of fields matches the private-API version there should be no issues in terms of compatibility between the different declared versions.  At runtime this structure should be indistinguishable from the private-API version for all practical purposes (barring reflection, which could detect the difference in the naming).</p>
<p>Anyways, this structure contains two fields; &#8216;<em>x1</em>&#8216;, which is a pointer to an array of functions that return integers, and &#8216;<em>x2</em>&#8216;, which is simply an integer.  Interestingly enough, the memory address of the returned data structure never differs by more than 256 bytes between calls, nor do the absolute values of &#8216;<em>x1</em>&#8216; or &#8216;<em>x2</em>&#8216; change.  And here is where things start to get a bit murky.  I&#8217;m going to forget about &#8216;<em>x2</em>&#8216; for a moment, as it is a simple type and its value never seems to vary.  &#8216;<em>x1</em>&#8216; is not so easy.</p>
<p>By inspecting the value of &#8216;<em>x1</em>&#8216;, I&#8217;ve determined that it references no more than 11 distinct functions (the 12th element in the result returned by CAFilter is <em>NULL</em>, and I assume that the <em>NULL</em> indicates the probable end of the meaningful data in the array).  Moreover, the addresses of the functions returned do not appear to vary, even between independent runs of the application.  Which implies to me that perhaps the result being returned is simply referencing some pre-existing object in memory.  </p>
<p>But this is all speculation on my part.  What&#8217;s needed here is more digging, so let&#8217;s create our own callback functions and see what we can discover about the way this data structure is being used by the core-animation framework.  We can do that by adding the following to the MyCAFilter implementation:</p>
<pre class="brush: cpp; title: ; notranslate">int (**originalFuncs)();  //cache for the actual function pointers

//copy/paste this 11 times, incrementing both '0's each time...it's inelegant but it works
int callback0( id firstParam, ... ) {
	int myIndex = 0;
	NSLog(@&quot;callback%d invoked, stack=%@&quot;, myIndex, [NSThread callStackSymbols]);
	
	va_list args;
	va_start(args, firstParam);
	int originalResult = originalFuncs[myIndex](firstParam, args);  //pass any params we recieved on to the original function; not sure if this is the correct way to do this
	
	NSLog(@&quot;callback%d will return result:  %d&quot;, myIndex, originalResult);
	
	return originalResult;
}</pre>
<p>And then by revising &#8216;<em>CA_copyRenderValue</em>&#8216; like so:</p>
<pre class="brush: cpp; title: ; notranslate">void* myCallbacks[11] = {&amp;callback0, &amp;callback1, &amp;callback2, &amp;callback3, &amp;callback4, &amp;callback5, &amp;callback6, &amp;callback7, &amp;callback8, &amp;callback9, &amp;callback10};

- (struct RenderValueResult*) CA_copyRenderValue {
	struct RenderValueResult* result = [delegate CA_copyRenderValue];	//TODO:  remove delegate
	struct RenderValueResult* myResult = malloc(sizeof(struct RenderValueResult));
	myResult-&gt;x2 = result-&gt;x2;  //just copy the integer component of the result; 65538?
	
	//see how many functions there are before we encounter a NULL
	int funcIndex = 0;
	while (result-&gt;x1[funcIndex] != NULL) {
		funcIndex++;
		if (funcIndex &gt;= 11) {
			NSLog(@&quot;CA_copyRenderValue;  NULL sigil not found, assuming max number of functions is 11!&quot;);
			break;
		}
	}
	NSLog(@&quot;CA_copyRenderValue;  found %d functions in delegate's result...&quot;, funcIndex);
	
	myResult-&gt;x1 = malloc(sizeof(int*) * (funcIndex + 1));		//we return this to the CA framework
	originalFuncs = malloc(sizeof(int*) * (funcIndex));			//we keep references to the original functions to use in our callbacks
	for (int index = 0; index &lt; funcIndex ; index++) {
		originalFuncs[index] = result-&gt;x1[index];		//cache the original function pointers
		myResult-&gt;x1[index] = myCallbacks[index];     //put dummy callbacks into the result
	}
	myResult-&gt;x1[funcIndex] = NULL;
	
    NSLog(@&quot;CA_copyRenderValue; result=0x%08X, result.x1=0x%08X, result.x2=%d&quot;, result, result-&gt;x1, result-&gt;x2);
	for (int index = 0; index &lt; funcIndex; index++) {
		NSLog(@&quot;CA_copyRenderValue; result-&gt;x1[%d]=0x%08X&quot;, index, result-&gt;x1[index]);
	}
	return myResult;
}</pre>
<p>Now if we run the application, we get the following output:</p>
<pre class="brush: plain; title: ; notranslate">2011-02-09 23:50:25.508 PageCurlDemo[10453:207] callback3 invoked, stack=(
	0   PageCurlDemo                        0x00006c2b callback3 + 50
	1   QuartzCore                          0x00d63347 CACopyRenderArray + 188
	2   QuartzCore                          0x00cc373e -[CALayer(CALayerPrivate) _copyRenderLayer:layerFlags:commitFlags:] + 1667
	3   QuartzCore                          0x00cc30b4 CALayerCopyRenderLayer + 55
	4   QuartzCore                          0x00cc11d2 _ZN2CA7Context12commit_layerEP8_CALayerjjPv + 122
	5   QuartzCore                          0x00cc10e1 CALayerCommitIfNeeded + 323
	6   QuartzCore                          0x00cc1069 CALayerCommitIfNeeded + 203
	7   QuartzCore                          0x00cc1069 CALayerCommitIfNeeded + 203
	8   QuartzCore                          0x00caf7b9 _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 1395
	9   QuartzCore                          0x00caf0d0 _ZN2CA11Transaction6commitEv + 292
	10  QuartzCore                          0x00cdf7d5 _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv + 99
	11  CoreFoundation                      0x00ef8fbb __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 27
	12  CoreFoundation                      0x00e8e0e7 __CFRunLoopDoObservers + 295
	13  CoreFoundation                      0x00e56bd7 __CFRunLoopRun + 1575
	14  CoreFoundation                      0x00e56240 CFRunLoopRunSpecific + 208
	15  CoreFoundation                      0x00e56161 CFRunLoopRunInMode + 97
	16  GraphicsServices                    0x0184c268 GSEventRunModal + 217
	17  GraphicsServices                    0x0184c32d GSEventRun + 115
	18  UIKit                               0x002d242e UIApplicationMain + 1160
	19  PageCurlDemo                        0x00002904 main + 102
	20  PageCurlDemo                        0x00002895 start + 53
)
2011-02-09 23:50:25.514 PageCurlDemo[10453:207] callback3 will return result:  9
2011-02-09 23:50:25.519 PageCurlDemo[10453:207] callback3 invoked, stack=(
	0   PageCurlDemo                        0x00006c2b callback3 + 50
	1   QuartzCore                          0x00ce5d12 _ZN2CA6Render7Encoder13encode_objectEPKNS0_6ObjectE + 30
	2   QuartzCore                          0x00ce670d _ZNK2CA6Render5Array6encodeEPNS0_7EncoderE + 113
	3   QuartzCore                          0x00ce5f24 _ZNK2CA6Render5Layer6encodeEPNS0_7EncoderE + 458
	4   QuartzCore                          0x00ce5cdb _ZN2CA6Render17encode_set_objectEPNS0_7EncoderEmjPNS0_6ObjectEj + 91
	5   QuartzCore                          0x00cc1215 _ZN2CA7Context12commit_layerEP8_CALayerjjPv + 189
	6   QuartzCore                          0x00cc10e1 CALayerCommitIfNeeded + 323
	7   QuartzCore                          0x00cc1069 CALayerCommitIfNeeded + 203
	8   QuartzCore                          0x00cc1069 CALayerCommitIfNeeded + 203
	9   QuartzCore                          0x00caf7b9 _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 1395
	10  QuartzCore                          0x00caf0d0 _ZN2CA11Transaction6commitEv + 292
	11  QuartzCore                          0x00cdf7d5 _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv + 99
	12  CoreFoundation                      0x00ef8fbb __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 27
	13  CoreFoundation                      0x00e8e0e7 __CFRunLoopDoObservers + 295
	14  CoreFoundation                      0x00e56bd7 __CFRunLoopRun + 1575
	15  CoreFoundation                      0x00e56240 CFRunLoopRunSpecific + 208
	16  CoreFoundation                      0x00e56161 CFRunLoopRunInMode + 97
	17  GraphicsServices                    0x0184c268 GSEventRunModal + 217
	18  GraphicsServices                    0x0184c32d GSEventRun + 115
	19  UIKit                               0x002d242e UIApplicationMain + 1160
	20  PageCurlDemo                        0x00002904 main + 102
	21  PageCurlDemo                        0x00002895 start + 53
)
2011-02-09 23:50:25.527 PageCurlDemo[10453:207] callback3 will return result:  9
2011-02-09 23:50:25.536 PageCurlDemo[10453:207] callback3 invoked, stack=(
	0   PageCurlDemo                        0x00006c2b callback3 + 50
	1   QuartzCore                          0x00ce5d34 _ZN2CA6Render7Encoder13encode_objectEPKNS0_6ObjectE + 64
	2   QuartzCore                          0x00ce670d _ZNK2CA6Render5Array6encodeEPNS0_7EncoderE + 113
	3   QuartzCore                          0x00ce5f24 _ZNK2CA6Render5Layer6encodeEPNS0_7EncoderE + 458
	4   QuartzCore                          0x00ce5cdb _ZN2CA6Render17encode_set_objectEPNS0_7EncoderEmjPNS0_6ObjectEj + 91
	5   QuartzCore                          0x00cc1215 _ZN2CA7Context12commit_layerEP8_CALayerjjPv + 189
	6   QuartzCore                          0x00cc10e1 CALayerCommitIfNeeded + 323
	7   QuartzCore                          0x00cc1069 CALayerCommitIfNeeded + 203
	8   QuartzCore                          0x00cc1069 CALayerCommitIfNeeded + 203
	9   QuartzCore                          0x00caf7b9 _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 1395
	10  QuartzCore                          0x00caf0d0 _ZN2CA11Transaction6commitEv + 292
	11  QuartzCore                          0x00cdf7d5 _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv + 99
	12  CoreFoundation                      0x00ef8fbb __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 27
	13  CoreFoundation                      0x00e8e0e7 __CFRunLoopDoObservers + 295
	14  CoreFoundation                      0x00e56bd7 __CFRunLoopRun + 1575
	15  CoreFoundation                      0x00e56240 CFRunLoopRunSpecific + 208
	16  CoreFoundation                      0x00e56161 CFRunLoopRunInMode + 97
	17  GraphicsServices                    0x0184c268 GSEventRunModal + 217
	18  GraphicsServices                    0x0184c32d GSEventRun + 115
	19  UIKit                               0x002d242e UIApplicationMain + 1160
	20  PageCurlDemo                        0x00002904 main + 102
	21  PageCurlDemo                        0x00002895 start + 53
)
2011-02-09 23:50:25.566 PageCurlDemo[10453:207] callback3 will return result:  9
2011-02-09 23:50:25.578 PageCurlDemo[10453:207] callback4 invoked, stack=(
	0   PageCurlDemo                        0x00006cca callback4 + 50
	1   QuartzCore                          0x00ce670d _ZNK2CA6Render5Array6encodeEPNS0_7EncoderE + 113
	2   QuartzCore                          0x00ce5f24 _ZNK2CA6Render5Layer6encodeEPNS0_7EncoderE + 458
	3   QuartzCore                          0x00ce5cdb _ZN2CA6Render17encode_set_objectEPNS0_7EncoderEmjPNS0_6ObjectEj + 91
	4   QuartzCore                          0x00cc1215 _ZN2CA7Context12commit_layerEP8_CALayerjjPv + 189
	5   QuartzCore                          0x00cc10e1 CALayerCommitIfNeeded + 323
	6   QuartzCore                          0x00cc1069 CALayerCommitIfNeeded + 203
	7   QuartzCore                          0x00cc1069 CALayerCommitIfNeeded + 203
	8   QuartzCore                          0x00caf7b9 _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 1395
	9   QuartzCore                          0x00caf0d0 _ZN2CA11Transaction6commitEv + 292
	10  QuartzCore                          0x00cdf7d5 _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv + 99
	11  CoreFoundation                      0x00ef8fbb __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 27
	12  CoreFoundation                      0x00e8e0e7 __CFRunLoopDoObservers + 295
	13  CoreFoundation                      0x00e56bd7 __CFRunLoopRun + 1575
	14  CoreFoundation                      0x00e56240 CFRunLoopRunSpecific + 208
	15  CoreFoundation                      0x00e56161 CFRunLoopRunInMode + 97
	16  GraphicsServices                    0x0184c268 GSEventRunModal + 217
	17  GraphicsServices                    0x0184c32d GSEventRun + 115
	18  UIKit                               0x002d242e UIApplicationMain + 1160
	19  PageCurlDemo                        0x00002904 main + 102
	20  PageCurlDemo                        0x00002895 start + 53
)</pre>
<p>Followed by a crash.  Something causes the attempt to invoke the fourth callback function to die; probably related to the questionable way that I&#8217;m passing arguments to it.  Not knowing what the proper signature for the callback functions is, I&#8217;ve made them all accept a variable number of &#8216;id&#8217; parameters, which should cover most cases.  However the best way to pass these arguments on to the original implementation is not clear.  </p>
<p>For what it&#8217;s worth, I tried a number of alternate ways to invoke this function, all of which resulted in a crash.  Skipping the invocation and just returning a hard-coded value from my callback prevented the crash, but didn&#8217;t result in any more callbacks being invoked.  Presumably core-animation noticed that my hard-coded return value didn&#8217;t match what it was expecting, and decided to abort the rest of its rendering transaction.  </p>
<p>And unfortunately, here is where I need to leave this interesting little diversion for now, unless/until I can figure out a way to move it forward.  If you have any suggestions please don&#8217;t hesitate to let me know.  I feel like I&#8217;m getting close to the answer here, but it&#8217;s still quite a ways away.</p>
<p><strong>Update</strong></p>
<p>If anyone is interested, you can download a complete <a href="http://codethink.no-ip.org/PageCurlDemo_modified.zip">XCode project</a> containing the latest revision of my code.  If you decide to take a crack at solving this problem, I wish you luck, and please do consider reporting back with your results.</p>
]]></content:encoded>
			<wfw:commentRss>https://codethink.no-ip.org/archives/320/feed</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
	</channel>
</rss>
