<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-3540073447780295551</id><updated>2011-09-16T19:55:57.623+08:00</updated><category term='CoreFoundation'/><category term='Command'/><category term='class-dump-z'/><category term='fun'/><category term='adkiller'/><category term='GriP'/><category term='iKeyEx'/><category term='QuickScroll'/><category term='CrashReporter'/><category term='hClipboard'/><category term='5RowQWERTY'/><title type='text'>networkpx Project Blog</title><subtitle type='html'>A blog about internals of iPhoneOS, and the networkpx project collection.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>88</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-5916725568259403373</id><published>2010-01-18T03:51:00.004+08:00</published><updated>2010-01-18T04:10:40.310+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='iKeyEx'/><category scheme='http://www.blogger.com/atom/ns#' term='CrashReporter'/><title type='text'>CrashReporter 0.2f available for testing; iKeyEx 0.3 sneak peak</title><content type='html'>&lt;a href="http://code.google.com/p/networkpx/downloads/detail?name=hk.kennytm.CrashReporter-0.2f.deb "&gt;CrashReporter 0.2f&lt;/a&gt; has been available for testing. This version should fully eliminate the crash caused by fat binaries. Also, it has a hidden preference enabling "Email crash report to developer" within CR. But to avoid swarm of emails by stupid users blaming the tertiary suspects without any grounds you're required to read the source code of CR to know how to enable it ;).&lt;br /&gt;&lt;br /&gt;Also, I have put up &lt;a href="http://code.google.com/p/networkpx/downloads/detail?name=hk.kennytm.iKeyEx3-0.3%7Ebeta1.deb"&gt;iKeyEx 0.3~beta1&lt;/a&gt; for anyone who needs the new feature to test. 0.3 is an intermediate version between 0.2 and 0.5 to address some keyboard developers' requests, in particular:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;When the key is a combining character, NFC is automatically applied.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;variantType = "immediate-accents" (e.g. Thai and Arabic) is available via "text with traits".&lt;/li&gt;&lt;br /&gt;&lt;li&gt;more-after and shift-after (e.g. Zhuyin keyboard and the apostrophe) can be explicitly turned on and off via the "after" traits.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;(0.5 shall support the "image" traits again, and thus keyboard theming; and the "star" operator in .cin IME.)&lt;br /&gt;&lt;br /&gt;And, I'd like to point out that, if you want to change the text of Return and Space in your keyboard, you can already do so by &lt;a href="http://code.google.com/p/networkpx/wiki/Creating_Keyboard_Bundles#strings.plist"&gt;strings.plist&lt;/a&gt;. This is supported from the start, not a new feature.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-5916725568259403373?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/5916725568259403373/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2010/01/crashreporter-02f-available-for-testing.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/5916725568259403373'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/5916725568259403373'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2010/01/crashreporter-02f-available-for-testing.html' title='CrashReporter 0.2f available for testing; iKeyEx 0.3 sneak peak'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-3499025536353194347</id><published>2010-01-06T05:51:00.002+08:00</published><updated>2010-01-06T06:10:16.249+08:00</updated><title type='text'>Two IDA Pro 5.x Scripts for iPhoneOS binaries</title><content type='html'>If you use IDA Pro to disasseble iPhoneOS binaries (Mach-O/ARM), you may find these scripts useful:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://networkpx.googlecode.com/svn/etc/idc/dyldinfo.idc"&gt;dyldinfo&lt;/a&gt;: This script lets IDA Pro understands the DYLD_INFO[_ONLY] command introduced in firmware 3.1. Running this recovers some missing symbols.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://networkpx.googlecode.com/svn/etc/idc/fixobjc2.idc"&gt;fixobjc2&lt;/a&gt;: For binaries built with Objective-C ABI 2, this script can find and label all Objective-C functions and ivar offsets.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;The result will look like this:&lt;br /&gt;&lt;img src="http://lh6.ggpht.com/_7Ek7e48Yovg/S0OuaXBZ8EI/AAAAAAAAAew/XBeq0w2jyLc/Untitled.png" /&gt;&lt;br /&gt;&lt;br /&gt;Because IDA doesn't allow "-" and spaces in names, the Objective-C function names are renamed like this:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;-[Foo bar:baz:] &amp;rarr; Foo.bar:baz:&lt;/li&gt;&lt;li&gt;+[Foo bar:baz:] &amp;rarr; @Foo.bar:baz:&lt;/li&gt;&lt;li&gt;-[Foo(Cat) bar:baz:] &amp;rarr; Foo(Cat).bar:baz:&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt; (Note: Try not to run fixobjc2 before dyldinfo, some information cannot be found.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-3499025536353194347?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/3499025536353194347/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2010/01/two-ida-pro-5x-scripts-for-iphoneos.html#comment-form' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/3499025536353194347'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/3499025536353194347'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2010/01/two-ida-pro-5x-scripts-for-iphoneos.html' title='Two IDA Pro 5.x Scripts for iPhoneOS binaries'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/_7Ek7e48Yovg/S0OuaXBZ8EI/AAAAAAAAAew/XBeq0w2jyLc/s72-c/Untitled.png' height='72' width='72'/><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-9016116996604086902</id><published>2009-12-29T01:52:00.005+08:00</published><updated>2009-12-29T21:03:18.583+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='iKeyEx'/><category scheme='http://www.blogger.com/atom/ns#' term='class-dump-z'/><category scheme='http://www.blogger.com/atom/ns#' term='CrashReporter'/><title type='text'>iKeyEx 0.2b, CrashReporter 0.2e, class-dump-z 0.2a released</title><content type='html'>Change log for &lt;a href="http://code.google.com/p/networkpx/downloads/detail?name=hk.kennytm.iKeyEx3-0.2b.deb "&gt;iKeyEx 0.2b&lt;/a&gt;:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;iKeyEx now uses &lt;a href="http://www.seanius.net/blog/2009/09/dpkg-triggers-howto/"&gt;postinst triggers&lt;/a&gt; to register layouts and input managers (&lt;a href="http://code.google.com/p/networkpx/source/detail?r=594"&gt;r594&lt;/a&gt;). Keyboard makers may leave out the [pre|post][inst|rm] scripts now because the list will be updated as your keyboard is installed or removed. (You still need a postinst script if you want to support automatic purging.) As a side effect, all input modes explicitly deleted by the user (via Mix and Match) will be added back in and activated. If you really don't want that layout, uninstall it from Cydia.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Fixed issue 470: iKeyEx left/right arrows don't work in multi-line text input controls (&lt;a href="http://code.google.com/p/networkpx/source/detail?r=593"&gt;r593&lt;/a&gt;).&lt;/li&gt;&lt;br /&gt;&lt;li&gt;No longer crashes for a layout with different landscape and portrait layout classes (&lt;a href="http://code.google.com/p/networkpx/source/detail?r=588"&gt;r588&lt;/a&gt;). Thanks erik_joya for reporting!&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Change log for &lt;a href="http://code.google.com/p/networkpx/downloads/detail?name=hk.kennytm.CrashReporter-0.2e.deb "&gt;CrashReporter 0.2e&lt;/a&gt;:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Fixed issue 481: CrashReport doesn't recognize FAT binaries. (&lt;a href="http://code.google.com/p/networkpx/source/detail?r=592"&gt;r592&lt;/a&gt;)&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Change log for &lt;a href="http://code.google.com/p/networkpx/downloads/detail?name=class-dump-z_0.2a.tar.gz "&gt;class-dump-z 0.2a&lt;/a&gt; &lt;del&gt;(except Windows, I need to reinstall VS2008 first)&lt;/del&gt;:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Support for "hints file" (&lt;a href="http://code.google.com/p/networkpx/source/detail?r=589"&gt;r589&lt;/a&gt;). See &lt;a href="http://code.google.com/p/networkpx/wiki/class_dump_z#Hints_file"&gt;this wiki page&lt;/a&gt; for detail. Thanks rpetrich for suggestion!&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-9016116996604086902?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/9016116996604086902/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/12/ikeyex-02b-crashreporter-02e-class-dump.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/9016116996604086902'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/9016116996604086902'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/12/ikeyex-02b-crashreporter-02e-class-dump.html' title='iKeyEx 0.2b, CrashReporter 0.2e, class-dump-z 0.2a released'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-6068486752387813202</id><published>2009-12-15T01:44:00.002+08:00</published><updated>2009-12-15T02:02:38.836+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='5RowQWERTY'/><category scheme='http://www.blogger.com/atom/ns#' term='iKeyEx'/><title type='text'>iKeyEx and 5-Row QWERTY 0.2a will be on Cydia soon.</title><content type='html'>The minor updates for iKeyEx (r579) and 5-Row QWERTY (r580) are released and will be on the Big Boss repo within 2 days. They can be downloaded from &lt;a href="http://code.google.com/p/networkpx/downloads/list"&gt;here&lt;/a&gt; as usual.&lt;br /&gt;&lt;br /&gt;These updates are to address some defects reported after 0.2 is put on the repo, for iKeyEx:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Keyboards for Hebrew, Arabic and other right-to-left languages will default to use right-to-left input direction. (&lt;a href="http://code.google.com/p/networkpx/source/detail?r=578"&gt;r578&lt;/a&gt;. Thanks DB42/OpenHebrew for reporting!)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Eliminated the built-in keyboard selection list in Settings, which became useless when iKeyEx is installed (it cannot be respected because the keyboard list is not safemode-safe otherwise). (&lt;a href="http://code.google.com/p/networkpx/source/detail?r=579"&gt;r579&lt;/a&gt;)&lt;/li&gt;&lt;/ul&gt; &lt;br /&gt;&lt;br /&gt;For 5-Row QWERTY:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The , and . keys are swapped back to their expected position. (Thanks Optimo for noticing!)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Reset the special characters won't duplicate the double quote (") anymore. (&lt;a href="http://code.google.com/p/networkpx/source/detail?r=580"&gt;r580&lt;/a&gt;)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Changing the layout flushes the cache correctly now. (&lt;a href="http://code.google.com/p/networkpx/issues/detail?id=471"&gt;issue 471&lt;/a&gt;)&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-6068486752387813202?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/6068486752387813202/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/12/ikeyex-and-5-row-qwerty-02a-will-be-on.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/6068486752387813202'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/6068486752387813202'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/12/ikeyex-and-5-row-qwerty-02a-will-be-on.html' title='iKeyEx and 5-Row QWERTY 0.2a will be on Cydia soon.'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-6032678245003823521</id><published>2009-12-04T18:07:00.003+08:00</published><updated>2009-12-04T18:39:52.366+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='iKeyEx'/><title type='text'>iKeyEx 0.2~rc1, Cangjie 0.2-3, CrashReporter 0.2d released</title><content type='html'>O hai, long time no post! &lt;br /&gt;&lt;br /&gt;This is because I have posted many material which were to be put here to the &lt;a href="http://www.iphonedevwiki.net/index.php?title=Main_Page"&gt;"iPhone Development Wiki"&lt;/a&gt; created by &lt;a href="http://www.howett.net/"&gt;Dustin Howett&lt;/a&gt;. (And also because of "schoolworks and tests" :p) This blog will remain for release notes only.&lt;br /&gt;&lt;br /&gt;Back to the main topic, there are 3 major releases today: &lt;strong&gt;&lt;a href="http://code.google.com/p/networkpx/downloads/detail?name=hk.kennytm.iKeyEx3-0.2%7Erc1.deb"&gt;iKeyEx 0.2~rc1&lt;/a&gt;&lt;/strong&gt;:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Different layouts in portrait and landscape orientation is supported again (r509, thanks DB42 for noticing)&lt;/li&gt;&lt;li&gt;CrashReporter support (r548)&lt;/li&gt;&lt;li&gt;Hooks only UIKit (r548).&lt;/li&gt;&lt;li&gt;Config file is now placed in ~/Library/Preferences/hk.kennytm.iKeyEx3.plist (r559).&lt;/li&gt;&lt;li&gt;Keyboard settings won't be lost due to Safe mode anymore.&lt;/li&gt;&lt;li&gt;.cin IME: Stop radical composition on failure by default.&lt;/li&gt;&lt;li&gt;.cin IME: Corrected sorting.&lt;/li&gt;&lt;li&gt;Other minor stuff.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;a href="http://code.google.com/p/networkpx/downloads/detail?name=hk.kennytm.Cangjie-0.2-3.deb"&gt;Cangjie 0.2-3:&lt;/a&gt;&lt;/strong&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The shift key will be disabled in the 倉頡QWERTY鍵盤. If you want to enter English letters in this keyboard layout, long press on a key (e.g. 水 -&gt; [水][E]).&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;a href="http://code.google.com/p/networkpx/downloads/detail?name=hk.kennytm.CrashReporter-0.2d.deb"&gt;CrashReporter 0.2d:&lt;/a&gt;&lt;/strong&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Made UIProgressHUD truly model to avoid crash due to accidental file deletion during symbolication.&lt;/li&gt;&lt;li&gt;Smarter suspect identification.&lt;/li&gt;&lt;li&gt;Symbolication in command line with the "-s" flag.&lt;/li&gt;&lt;li&gt;Complains if you did not install syslogd :)&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-6032678245003823521?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/6032678245003823521/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/12/ikeyex-02rc1-cangjie-02-3-crashreporter.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/6032678245003823521'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/6032678245003823521'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/12/ikeyex-02rc1-cangjie-02-3-crashreporter.html' title='iKeyEx 0.2~rc1, Cangjie 0.2-3, CrashReporter 0.2d released'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-4570669641055379376</id><published>2009-09-28T00:50:00.002+08:00</published><updated>2009-09-28T00:54:45.462+08:00</updated><title type='text'>Sorry Ollie Kett but...</title><content type='html'>can I sell this scriptlet for $0.99?&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;code&gt;javascript:var s=document.documentElement.outerHTML.replace(/&amp;amp;/g,"&amp;amp;amp;").replace(/&amp;lt;/g,"&amp;amp;lt;").replace(/&amp;gt;/g,"&amp;amp;gt;").replace(/\n/g,"&amp;lt;br/&amp;gt;");document.open();document.write(s);document.close();&lt;/code&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;em&gt;Disclaimer: This is &lt;strong&gt;not&lt;/strong&gt; how Source Explore works. I did not even buy, try, pirate, or do anything with this app.&lt;/em&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-4570669641055379376?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/4570669641055379376/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/09/sorry-ollie-kett-but.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/4570669641055379376'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/4570669641055379376'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/09/sorry-ollie-kett-but.html' title='Sorry Ollie Kett but...'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-4147781357802295220</id><published>2009-09-26T02:05:00.005+08:00</published><updated>2009-12-10T23:07:47.965+08:00</updated><title type='text'>Compiling iPhoneOS (3.1) apps with Xcode 3.2 without Provisioning Profile</title><content type='html'>Note: I don't know if &lt;a href="http://iphonesdkdev.blogspot.com/2009/06/use-xcode-312-to-build-sdk-30-app-to-30.html"&gt;this method&lt;/a&gt; still works, and I don't care. (And &lt;strong&gt;do not&lt;/strong&gt; use the &lt;tt&gt;dd&lt;/tt&gt; method mentioned in the article. It is extremely fragile to patch a binary file.)&lt;br /&gt;&lt;br /&gt;Note 2: Please also check &lt;a href="http://iphonedevwiki.howett.net/index.php?title=Xcode#Developing_without_Provisioning_Profile"&gt;http://iphonedevwiki.howett.net/index.php?title=Xcode#Developing_without_Provisioning_Profile&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;I want to compile.&lt;/h3&gt;&lt;br /&gt;This is easiest to solve. To compile you still need a certificate that can code-sign, but think this as a lip-service. &lt;a href="http://developer.apple.com/mac/library/documentation/Security/Conceptual/CodeSigningGuide/Procedures/Procedures.html"&gt;Here is the procedure to create a self-signed code-signing certificate using Keychain Access&lt;/a&gt;. Make sure you create the certificate in the "login" (default) keychain, not the "System" keychain. After the certificate is created, perform these steps:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Open &lt;tt&gt;/Developer/Platforms/iPhoneOS.platform/Info.plist&lt;/tt&gt;. (Backup if you want to be safe.)&lt;/li&gt;&lt;li&gt;Go to line 46. Replace the &lt;tt&gt;XCiPhoneOSCodeSignContext&lt;/tt&gt; with &lt;tt&gt;XCCodeSignContext&lt;/tt&gt;&lt;/li&gt;&lt;li&gt;Go to line 79. Replace the &lt;tt&gt;XCiPhoneOSCodeSignContext&lt;/tt&gt; with &lt;tt&gt;XCCodeSignContext&lt;/tt&gt;&lt;/li&gt;&lt;li&gt;Save the file.&lt;/li&gt;&lt;li&gt;Restart Xcode.&lt;/li&gt;&lt;li&gt;Compile!&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;After doing this, you can't use entitlements with Xcode anymore. But you have &lt;tt&gt;ldid -Sxyz.xml&lt;/tt&gt; that does the same job.&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The theory behind this is simple. When Xcode wants to code-sign, it has to consult DevToolsCore.framework on the procedures to code sign. The procedures are coded in the XCCodeSignContext class. The iPhoneOS placed more restrictions on the code-signing requirements, e.g. you must have a provision file. These extra procedures are provided in the class XCiPhoneOSCodeSignContext, as a plug-in at &lt;tt&gt;/Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Plug-ins/iPhoneOS Build System Support.xcplugin&lt;/tt&gt;. Xcode isn't omniscience, so something must tell it that XCiPhoneOSCodeSignContext should be used, instead of the default XCCodeSignContext. This thing is the &lt;tt&gt;/Developer/Platforms/iPhoneOS.platform/Info.plist&lt;/tt&gt;. In the past (iPhoneOS 2.x day), you add the PROVISIONING_PROFILE_[ALLOWED|REQUIRED] keys to give extra instructions to the plug-in, &lt;em&gt;which it can promptly ignore&lt;/em&gt;. That's why eventually you need to take the dangerous way of binary-patching the plug-in. But why not just hide XCiPhoneOSCodeSignContext entirely? This is my hack's principle - tell Xcode to meet the new boss, same as the old boss. &lt;br /&gt;&lt;br /&gt;&lt;h3&gt;I want to install and debug too.&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;(Note: I'm not fond of patching MobileInstallation.framework. In fact, on 3.1 there's no framework you can statically patch with.)&lt;br /&gt;&lt;br /&gt;Unfortunately, installing is more complex than compiling because there are much more checking in the device side. Therefore the procedures will be so complex that ordinary developers should not follow ;).&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Make sure you have ldid on Mac. (e.g. &lt;a href="http://code.google.com/p/networkpx/downloads/detail?name=ldid"&gt;this&lt;/a&gt;). Place it in &lt;tt&gt;/usr/local/bin&lt;/tt&gt;.&lt;/li&gt;&lt;li&gt;Create the file &lt;tt&gt;/usr/local/bin/ldid2&lt;/tt&gt;. Make it executable. Fill it with:&lt;blockquote&gt;&lt;pre&gt;#!/bin/sh&lt;br /&gt;&lt;br /&gt;hasGTA=`expr "$*" : '.* -gta .*'`;&lt;br /&gt;objpath=${!#}/`expr ${!#} : '.*/\([^/]\{1,\}\)\.app$'`;&lt;br /&gt;&lt;br /&gt;if [[ $hasGTA == 0 ]]; then&lt;br /&gt; /usr/local/bin/ldid -S $objpath;&lt;br /&gt;else&lt;br /&gt; TF=`mktemp -t x`;&lt;br /&gt; echo "&amp;lt;!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"&amp;gt;&amp;lt;plist version=\"1.0\"&amp;gt;&amp;lt;dict&amp;gt;&amp;lt;key&amp;gt;get-task-allow&amp;lt;/key&amp;gt;&amp;lt;true/&amp;gt;&amp;lt;/dict&amp;gt;&amp;lt;/plist&amp;gt;" &amp;gt; $TF;&lt;br /&gt; /usr/local/bin/ldid -S$TF $objpath;&lt;br /&gt; rm $TF;&lt;br /&gt;fi;&lt;/pre&gt;&lt;/blockquote&gt;&lt;/li&gt;&lt;li&gt;Open &lt;tt&gt;/Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Plug-ins/iPhoneOS Build System Support.xcplugin/Contents/Resources/iPhoneCodeSign.xcspec&lt;/tt&gt;&lt;/li&gt;&lt;li&gt;Replace the line saying &lt;tt&gt;CommandLine = "/usr/bin/codesign"&lt;/tt&gt; with &lt;tt&gt;CommandLine = "/usr/local/bin/ldid2"&lt;/tt&gt;&lt;/li&gt;&lt;li&gt;Now, copy &lt;tt&gt;/usr/libexec/installd&lt;/tt&gt; from your device to your Mac.&lt;/li&gt;&lt;li&gt;Run this:&lt;blockquote&gt;&lt;pre&gt;install_name_tool -change /usr/lib/libmis.dylib /usr/lib/libmiss.dylib installd&lt;br /&gt;ldid -S installd&lt;/pre&gt;&lt;/blockquote&gt;&lt;/li&gt;&lt;li&gt;Now, create a file named &lt;tt&gt;libmiss.c&lt;/tt&gt;, and enter these into the file:&lt;blockquote&gt;&lt;pre&gt;extern int MISValidateSignature() { return 0; }&lt;/pre&gt;&lt;/blockquote&gt;&lt;/li&gt;&lt;li&gt;Compile libmiss.c to libmiss.dylib with gcc targeting iPhone. Make sure t you have all these flags:&lt;blockquote&gt;&lt;pre&gt;-dynamiclib&lt;br /&gt;-install_name /usr/lib/libmiss.dylib&lt;br /&gt;-current_version 1&lt;br /&gt;-compatibility_version 1&lt;br /&gt;-Wl,-reexport-lmis&lt;br /&gt;-flat_namespace&lt;/pre&gt;&lt;/blockquote&gt;&lt;/li&gt;&lt;li&gt;ldid -S libmiss.dylib, of course.&lt;/li&gt;&lt;li&gt;Copy the new installd to the device's &lt;tt&gt;/usr/libexec&lt;/tt&gt;, and the libmiss.dylib to the device's &lt;tt&gt;/usr/lib&lt;/tt&gt;.&lt;/li&gt;&lt;li&gt;Restart Xcode.&lt;/li&gt;&lt;li&gt;Install!&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;If you want to debug, add the &lt;tt&gt;-gta&lt;/tt&gt; flag in "Other Code Signing Flags" in your Xcode Project.&lt;br /&gt;&lt;br /&gt;OK, so WTF is going on? The first 4 steps allows you to debug the app on the device. The essence of this is replace codesign with ldid. Why this is necessary? Because of the change in Part 1, entitlements are no longer respected. But to debug you must have the get-task-allow entitlement. To fix it, we have to entirely replace codesign with our executable that adds the entitlement ourselves. ldid2 is created with this purpose.&lt;br /&gt;&lt;br /&gt;The rest of the steps allows mobile installation to succeed without validation. When the app is installed from Xcode, "mobile_installation_proxy" is invoked, which spawned "installd". The validation part of installd is this:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt; +00cd4 0000af2c 0010A0E3 loc_000cd4: mov               r1,#0x0&lt;br /&gt; +00cd8 0000af30 D19701EB             bl                MISValidateSignature (stub)&lt;br /&gt; +00cdc 0000af34 005050E2             subs              r5,r0,#0x0&lt;br /&gt; +00ce0 0000af38 0600000A             beq               loc_000d00&lt;br /&gt; +00ce4 0000af3c 54049FE5             ldr               r0,[pc,#0x454]                    ; -&amp;gt; 0xb398 "verify_executable"&lt;br /&gt; +00ce8 0000af40 5C149FE5             ldr               r1,[pc,#0x45c]                    ; -&amp;gt; 0xb3a4 "Could not validate signature: %x"&lt;br /&gt; +00cec 0000af44 0520A0E1             mov               r2,r5                             ; "_CodeSignature/CodeResources"&lt;br /&gt; +00cf0 0000af48 C9E3FFEB             bl                proc_00003E74&lt;br /&gt; +00cf4 0000af4c 0400A0E1             mov               r0,r4&lt;br /&gt; +00cf8 0000af50 B49701EB             bl                CFRelease (stub)&lt;br /&gt; +00cfc 0000af54 060000EA             b                 loc_000d1c&lt;/pre&gt;&lt;/blockquote&gt;If we can force MISValidateSignature() to always return 0, any binaries will pass the test. This function is part of libmis.dylib, which is now part of the shared cache, so you can't binary patch this file. Replacing the implementation of a function is a perfect job with MobileSubstrate, unfortunately, no matter how I tried MS can't be injected. Therefore I use a trick: create a "proxy dynamic library" that changes only the MISValidateSignature function, and let the rest pass through. This is the purpose of libmiss.dylib. First, install_name_tool is used to repoint the libmis.dylib in installd to libmiss.dylib. Then, in libmiss.dylib we define a single function, MISValidateSignature, which returns 0 as we wanted. It linked with libmis.dylib, and reexport all the symbols so that the original symbols can still be found. But we have to use flat namespace to make sure our new MISValidateSignature can shadow the old one. Finally, there is a quirk in installd that required the dylib to be at version 1.0.0, so the -compatibility_version and -current_version flags are added.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Ouch these are all so difficult. Any easier methods?&lt;/h3&gt;&lt;br /&gt;Yes. Pay $99 to Apple. :p&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-4147781357802295220?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/4147781357802295220/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/09/compiling-iphoneos-31-apps-with-xcode.html#comment-form' title='43 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/4147781357802295220'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/4147781357802295220'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/09/compiling-iphoneos-31-apps-with-xcode.html' title='Compiling iPhoneOS (3.1) apps with Xcode 3.2 without Provisioning Profile'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>43</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-6817340375721841639</id><published>2009-09-25T12:21:00.005+08:00</published><updated>2009-09-25T13:32:22.179+08:00</updated><title type='text'>GreenTea devices — You can still use Maps.</title><content type='html'>I have forcefully enabled GreenTea on my device (with MobileSubstrate) but &lt;strong&gt;almost everything behaves normally&lt;/strong&gt; (iTunes is still accessible, YouTube is not hidden, Maps shows everywhere, etc.). The only difference I've noticed is:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;There is no Hybrid mode in Maps when GreenTea is on.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Oh well.&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;hr /&gt;&lt;br /&gt;Anyway, the string "GreenTea" can be found in at least these 5 binaries: SpringBoard, MapKit, GMM, GraphicsServices, PhotoLibrary.&lt;br /&gt;&lt;br /&gt;In SpringBoard, GreenTea can be found in these scenarios:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;CFSTR("SBShowITunesStoreOnGreenTea") // in -[SpringBoard userDefaultsDidChange:]&lt;/li&gt;&lt;li&gt;kGSGreenTeaDeviceCapability near @selector(allowYouTube)&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;In MapKit, &lt;br /&gt;&lt;ul&gt;&lt;li&gt;-[UIDevice(MKAdditions) _mapkit_isChinaDevice] which returns GSSystemHasCapability(kGSGreenTeaDeviceCapability)&lt;/li&gt;&lt;li&gt;Some non-harmful changes in MKSearch***&lt;/li&gt;&lt;li&gt;In MKMaxZoomLevelForCoordinate(), if _mapkit_isChinaDevice returns true, jumps over the test against MKCoordinateIsInSouthKorea() // wtf is going on?!&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;In GMM,&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Changes the server to http://www.google.cn/glm/...&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;In PhotoLibrary,&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Something related to MMS.&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-6817340375721841639?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/6817340375721841639/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/09/greentea-devices-you-can-still-use-maps.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/6817340375721841639'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/6817340375721841639'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/09/greentea-devices-you-can-still-use-maps.html' title='GreenTea devices — You can still use Maps.'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-2982700090598957038</id><published>2009-09-24T04:00:00.003+08:00</published><updated>2009-09-24T05:07:31.537+08:00</updated><title type='text'>China, no Google Maps for you (maybe)</title><content type='html'>Today I was making the &lt;a href="http://github.com/kennytm/iphone-private-frameworks/tree/master/GraphicsServices/"&gt;API for GraphicsServices&lt;/a&gt;, and found something... interesting.&lt;br /&gt;&lt;br /&gt;Since 3.0 it was "well known" that there is a mysterious capability called as "Green Tea". Nothing was known except for this funny name. Things start to get clear in the 3.1 firmware. The GraphicsServices of 3.1 has a &lt;a href="http://github.com/kennytm/iphone-private-frameworks/blob/master/GraphicsServices/GSMaps.h"&gt;new set of API&lt;/a&gt; for querying some properties of Maps and MapKit. Strangely, in the disassembly of these functions, the mysterious "Green Tea" capability was refered, e.g.&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;Boolean GSMapKitUserShifting() {&lt;br /&gt;  static CFStringRef gtDefault = CFSTR("MapKitUserShiftingGreenTea");&lt;br /&gt;  static CFStringRef ngtDefault = CFSTR("MapKitUserShiftingNonGreenTea");&lt;br /&gt;  if (GSSystemHasCapability(CFSTR("green-tea")))&lt;br /&gt;    return GetMapsDefault(gtDefault);&lt;br /&gt;  else&lt;br /&gt;    return GetMapsDefault(ngtDefault);&lt;br /&gt;}&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;It means the "Green Tea" capability is related to Maps, and takes different default values. No big deal right?&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Moving downwards shows a more horrific picture, e.g. the GSMapKitAvailable() function is&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;Boolean GSMapKitAvailable() {&lt;br /&gt;  if (!GSSystemHasCapability(CFSTR("green-tea")))&lt;br /&gt;    return true;&lt;br /&gt;  else {&lt;br /&gt;    static CFStringRef defaultName = CFSTR("MapKitAvailableGreenTea");&lt;br /&gt;    return GetMapsDefault(defaultName);&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;Ah, when a device is "Not Green Tea", it directly says MapKit is available, but when the device is "Green Tea" it needs to check a default value? Sounds more like a restriction than a capability!&lt;br /&gt;&lt;br /&gt;Further down, in GSMapsVisible(),&lt;blockquote&gt;&lt;pre&gt;static Boolean _mapsLastVisible;&lt;br /&gt;Boolean GSMapsVisible() {&lt;br /&gt;  static Boolean _registeredListener = false;&lt;br /&gt;  _mapsLastVisible = _GSMapsVisible();&lt;br /&gt;  if (!_registeredListener) {&lt;br /&gt;    CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, CarrierBundleChangedHandler, CFSTR("NewCarrierNotification"), NULL, 0);&lt;br /&gt;    _registeredListener = true;&lt;br /&gt;  }&lt;br /&gt;  return _mapsLastVisible;&lt;br /&gt;}&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;_GSMapsVisible() has a same "Green Tea" check as GSMapKitAvailable(). Strangely, it subscribes to the "New Carrier" Darwin notification, which probably means the Carrier can decide if Maps is visible or not (if com.apple.GMM.plist can be edited)!&lt;br /&gt;&lt;br /&gt;So what does this "Green Tea" capability refers to? If we turn to GMM.framework, we can find the following code:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt; +00244 0000ba5c             ldr               r0,[pc,r0]                        ; -&gt; kGSGreenTeaDeviceCapability _mh_dylib_header&lt;br /&gt; +00248 0000ba60             ldr               r0,[r0]                           ; -&gt; _mh_dylib_header&lt;br /&gt; +0024c 0000ba64             bl                GSSystemHasCapability (stub)&lt;br /&gt; +00250 0000ba68             ldr               r3,[pc,#0x1bc]                    ; -&gt; 0xbc2c&lt;br /&gt; +00254 0000ba6c             add               r3,pc,r3                          ; GMM::Factory::isChinaDevice_&lt;br /&gt; +00258 0000ba70             subs              r0,r0,#0x0&lt;br /&gt; +0025c 0000ba74             movne             r0,#0x1&lt;br /&gt; +00260 0000ba78             strb              r0,[r3]                           ; -&gt; GMM::Factory::isChinaDevice_&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;So having "Green Tea" is equivalent to China device! Let's recap:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Green Tea &amp;rArr; Maps can be disabled.&lt;/li&gt;&lt;li&gt;Visibility of Maps is affected by Carrier&lt;/li&gt;&lt;li&gt;Green Tea = China Device&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;so a logical conclusion could be &lt;strong&gt;Carriers in China can affect the visibility of iPhone's Maps&lt;/strong&gt;. Could it be a political decision? No matter what, China's iPhone already has no WiFi, but turns out it could be more crippled than expected.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-2982700090598957038?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/2982700090598957038/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/09/china-no-google-maps-for-you-maybe.html#comment-form' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/2982700090598957038'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/2982700090598957038'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/09/china-no-google-maps-for-you-maybe.html' title='China, no Google Maps for you (maybe)'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-7378926144851978777</id><published>2009-09-20T19:54:00.003+08:00</published><updated>2009-09-20T20:09:22.541+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='class-dump-z'/><title type='text'>class-dump-z 0.2-0 released.</title><content type='html'>(The version jump is mainly because every other project is moving to 0.2 era.)&lt;br /&gt;&lt;br /&gt;Download: &lt;a href="http://code.google.com/p/networkpx/downloads/detail?name=class-dump-z_0.2-0.tar.gz"&gt;http://code.google.com/p/networkpx/downloads/detail?name=class-dump-z_0.2-0.tar.gz&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Note:&lt;/strong&gt; Mac OS X 10.6 is required in this version. &lt;br /&gt;&lt;br /&gt;What's changed:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Universal binary is supported. You can choose different architectures with the -u switch. (Not -arch or --arch because I didn't use getopt_long.)&lt;/li&gt;&lt;li&gt;Completely recognizes the new __LINKEDIT format. XXUnknownSuperclass shall no longer appears for 3.1 binaries.&lt;/li&gt;&lt;li&gt;__attribute__((visibility("hidden"))) will be included as well when the class is not exported (e.g. UIKeyboardLayoutStar).&lt;/li&gt;&lt;li&gt;Options to hide categories and protocols.&lt;/li&gt;&lt;li&gt;Sort class alphabetically, but keep class methods and -init methods on top (suggested by ashikase)&lt;/li&gt;&lt;li&gt;Option to choose between &lt;tt&gt;+(void)foo;&lt;/tt&gt; and &lt;tt&gt;+ (void)foo;&lt;/tt&gt;. (suggested by ashikase)&lt;/li&gt;&lt;li&gt;Fixes a minor bug where timeOut:(int)out was written instead of timeOut:(int)anOut.&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-7378926144851978777?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/7378926144851978777/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/09/class-dump-z-02-0-released.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/7378926144851978777'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/7378926144851978777'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/09/class-dump-z-02-0-released.html' title='class-dump-z 0.2-0 released.'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-8377406339610453726</id><published>2009-09-20T03:14:00.004+08:00</published><updated>2009-09-20T19:54:13.071+08:00</updated><title type='text'>About the LC_DYLD_INFO[_ONLY] command.</title><content type='html'>With the introduction of the new __LINKEDIT format in iPhoneOS 3.1, many tools in the open toolchain are broken. This is all due to the unknown new commands LC_DYLD_INFO[_ONLY]. Although it's known to exist by many now, I found no useful documentation about this new format. Therefore, I'll outline what it is. Alternatively, you can study the source code of &lt;a href="http://www.opensource.apple.com/source/ld64/ld64-96.5/src/other/dyldinfo.cpp"&gt;dyldinfo&lt;/a&gt; which contains every information here.&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;The LC_DYLD_INFO[_ONLY] commands&lt;/h3&gt;&lt;br /&gt;These load commands are numerically 0x22 and 0x80000022. The only difference between them are LC_DYLD_INFO_ONLY will abort loading when dyld doesn't understand the new format.&lt;br /&gt;&lt;br /&gt;The structure of this load command has been &lt;a href="http://pastie.org/572025"&gt;described&lt;/a&gt; before. It refers to 5 chunks of data in the __LINKEDIT segment, which are called &lt;strong&gt;rebase&lt;/strong&gt;, &lt;strong&gt;bind/weak_bind/lazy_bind&lt;/strong&gt;, and &lt;strong&gt;export&lt;/strong&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;bind/weak_bind/lazy_bind&lt;/h3&gt;&lt;br /&gt;These 3 chunks are encoded with the same format. Please think of the data in these chunks as a tiny assembly language, which the only purpose is to "bind" (map) VM addresses to a symbol.&lt;br /&gt;&lt;br /&gt;The encoding of each data is of the form:&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Bit 7&lt;/td&gt;&lt;td&gt;6&lt;/td&gt;&lt;td&gt;5&lt;/td&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;0&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td colspan="4"&gt;opcode&lt;/td&gt;&lt;td colspan="4"&gt;imm operand&lt;/td&gt;&lt;td&gt;(extra data)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;So there are at most 16 different opcodes can be used, and the immediate operand can hold a value 0 to 15. But most of the times a value &gt;15, or even non-numeric data is needed. In these cases, extra data will be appended after this byte.&lt;br /&gt;&lt;br /&gt;A large number is encoded in the &lt;a href="http://en.wikipedia.org/wiki/LEB128"&gt;"LEB128" format&lt;/a&gt;. In this format, each byte is separated into a "continue bit" (bit 7) and the "digits" (bit 0-6).&lt;br /&gt;&lt;br /&gt;Suppose we want to encode the number 123456 in LEB128. Firstly, we write 123456 in binary, and separated into groups of 7 digits: &lt;strong&gt;0000111,1000100,1000000&lt;/strong&gt;. Then we insert the "continue bit" as 1, except the most significant one, which is 0 to signal the end of the number: &lt;strong&gt;&lt;u&gt;0&lt;/u&gt;0000111,&lt;u&gt;1&lt;/u&gt;1000100,&lt;u&gt;1&lt;/u&gt;1000000&lt;/strong&gt;. Finally, it should be in little endian, so we flip it around and write out the result: &lt;strong&gt;0xC0 0xC4 0x07&lt;/strong&gt;.&lt;br /&gt;&lt;br /&gt;Apple so far defined 13 opcodes:&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;opcode&lt;/th&gt;&lt;th&gt;Symbol&lt;/th&gt;&lt;th&gt;Meaning&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;0&lt;/td&gt;&lt;td&gt;DONE&lt;/td&gt;&lt;td&gt;Finished defining a symbol.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;SET_DYLIB_ORDINAL_IMM&lt;/td&gt;&lt;td&gt;Set the &lt;em&gt;library ordinal&lt;/em&gt; of the current symbol to the &lt;em&gt;imm operand&lt;/em&gt;.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;SET_DYLIB_ORDINAL_ULEB&lt;/td&gt;&lt;td&gt;Same as above, but the library ordinary is read from the unsigned LEB128-encoded extra data.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;SET_DYLIB_SPECIAL_IMM&lt;/td&gt;&lt;td&gt;Same as above, but the ordinary as set as &lt;em&gt;negative&lt;/em&gt; of imm. Typical values are:&lt;ul&gt;&lt;li&gt;0 = SELF&lt;/li&gt;&lt;li&gt;-1 = MAIN_EXECUTABLE&lt;/li&gt;&lt;li&gt;-2 = FLAT_LOOKUP&lt;/li&gt;&lt;/ul&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;SET_SYMBOL_TRAILING_FLAGS_IMM&lt;/td&gt;&lt;td&gt;Set flags of the symbol in imm, and the symbol name as a C string in the extra data. The flags are:&lt;ul&gt;&lt;li&gt;1 = WEAK_IMPORT&lt;/li&gt;&lt;li&gt;8 = NON_WEAK_DEFINITION&lt;/li&gt;&lt;/ul&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;5&lt;/td&gt;&lt;td&gt;SET_TYPE_IMM&lt;/td&gt;&lt;td&gt;Set the type of symbol as imm. Known values are:&lt;ul&gt;&lt;li&gt;1 = POINTER&lt;/li&gt;&lt;li&gt;2 = TEXT_ABSOLUTE32&lt;/li&gt;&lt;li&gt;3 = TEXT_PCREL32&lt;/li&gt;&lt;/ul&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;6&lt;/td&gt;&lt;td&gt;SET_ADDEND_SLEB&lt;/td&gt;&lt;td&gt;Set the addend of the symbol as the signed LEB128-encoded extra data. Usage unknown.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;7&lt;/td&gt;&lt;td&gt;SET_SEGMENT_AND_OFFSET_ULEB&lt;/td&gt;&lt;td&gt;Set that the symbol can be found in the imm-th segment, at an offset found in the extra data.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;8&lt;/td&gt;&lt;td&gt;ADD_ADDR_ULEB&lt;/td&gt;&lt;td&gt;Increase the offset (as above) by the LEB128-encoded extra data.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;9&lt;/td&gt;&lt;td&gt;DO_BIND&lt;/td&gt;&lt;td&gt;Define a symbol from the gathered information. Increase the offset by 4 (or 8 on 64-bit targets) after this operation.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;A&lt;/td&gt;&lt;td&gt;DO_BIND_ADD_ADDR_ULEB&lt;/td&gt;&lt;td&gt;Same as above, but besides the 4 byte increment, the extra data is also added.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;B&lt;/td&gt;&lt;td&gt;DO_BIND_ADD_ADDR_IMM_SCALED&lt;/td&gt;&lt;td&gt;Same as DO_BIND, but an extra imm*4 bytes is also added.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;C&lt;/td&gt;&lt;td&gt;DO_BIND_ULEB_TIMES_SKIPPING_ULEB&lt;/td&gt;&lt;td&gt;This is a very complex operation. &lt;em&gt;Two&lt;/em&gt; unsigned LEB128-encoded numbers are read off from the extra data. The first is the count of symbols to be added, and the second is the bytes to skip after a symbol is added. In pseudocode, all it does is:&lt;blockquote&gt;&lt;pre&gt;for i = 1 to count&lt;br /&gt; define symbol&lt;br /&gt; offset += 4 + skip&lt;br /&gt;end for&lt;/pre&gt;&lt;/blockquote&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;For example, we want to bind the address 0x2020 (of the __DATA section, starting at 0x2000) to the symbol _XXHello, which is defined in the 9th loaded dylib, Hello.dylib. We would perform the following operations:&lt;pre&gt;SET_DYLIB_ORDINAL_IMM(9)&lt;br /&gt;SET_SYMBOL_TRAILING_FLAGS_IMM(0, "_XXHello")&lt;br /&gt;SET_SEGMENT_AND_OFFSET_ULEB(2, 0x20)  ; usually __DATA is the 2nd segment.&lt;br /&gt;DO_BIND()&lt;/pre&gt;&lt;br /&gt;So in binary it will be&lt;br /&gt;&lt;pre&gt;0x19 0x40 "_XXHello\0" 0x72 0x20 0x90&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;rebase&lt;/h3&gt;&lt;br /&gt;I don't think rebase is useful, and rebase uses a similar approach to code rebase info as bind, so I'm ignoring it here.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;export&lt;/h3&gt;&lt;br /&gt;Unlike bind, export is an entirely different beast. The content of the export chunk defines a &lt;em&gt;trie&lt;/em&gt;, or a prefix tree. A node in this trie is encoded as:&lt;br /&gt;&lt;blockquote&gt;Node = «uint8_t terminal_size» [Terminal] «uint8_t child_count» [Child] [Child] [Child] ...&lt;br /&gt;Child = «char* suffix» «uleb128 offset»&lt;br /&gt;Terminal = «uleb128 flags» «uleb128 address»&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Known flags are:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;1 = THREAD_LOCAL&lt;/li&gt;&lt;li&gt;4 = WEAK_DEFINITION&lt;/li&gt;&lt;li&gt;8 = INDIRECT_DEFINITION&lt;/li&gt;&lt;li&gt;0x10 = HAS_SPECIALIZATIONS&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;For example, if a dylib exported _XXHello at 0x1022 and _XXWorld at 0x1064, and _XXHelloWorld2 at 0x1558. A trie that represent these symbols would be:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;_XX - [Hello] - [World2]&lt;br /&gt;   \&lt;br /&gt;     [World]&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So we encode our root node as&lt;br /&gt;&lt;pre&gt;00 01 "_XX\0" (offset to _XX)&lt;/pre&gt;&lt;br /&gt;and _XX as&lt;br /&gt;&lt;pre&gt;00 02 "Hello\0" (offset to Hello) "World\0" (offset to World)&lt;/pre&gt;&lt;br /&gt;if we place the _XX node right after the root node the offset would be 7, so the root node is&lt;br /&gt;&lt;pre&gt;00 01 "_XX\0" 07&lt;/pre&gt;&lt;br /&gt;The offset of the rest can be obtained like this. Now for the Hello node, since it defined a symbol, we have to fill in the Terminal info:&lt;br /&gt;&lt;pre&gt;05 00 A2 20 /*=0x1022*/ 01 "World2\0" (offset to World2)&lt;/pre&gt;&lt;br /&gt;etc.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-8377406339610453726?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/8377406339610453726/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/09/about-lcdyldinfoonly-command.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/8377406339610453726'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/8377406339610453726'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/09/about-lcdyldinfoonly-command.html' title='About the LC_DYLD_INFO[_ONLY] command.'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-7754587954469999500</id><published>2009-09-18T22:16:00.003+08:00</published><updated>2009-09-19T01:31:43.067+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='QuickScroll'/><title type='text'>QuickScroll 2.2a should be available on Cydia soon.</title><content type='html'>QuickScroll &lt;del&gt;2.2&lt;/del&gt; &lt;ins&gt;2.2a&lt;/ins&gt; is released, and this marks the completion (so far) of the QuickScroll project. Thanks to the gdb for 3.1 I've finally squashed the "HiCalc" bug. I have already submitted it to BigBoss and should be available in a day. If you can't wait, you can still download from &lt;a href="http://code.google.com/p/networkpx/downloads/detail?name=hk.kennytm.quickscroll2-0.2-2a.deb"&gt;here&lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;Change log from 2.1a:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The scrolling indicator is no longer visible when scrollbar is used.&lt;/li&gt;&lt;li&gt;You should be able to use the scroller in HiCalc and other apps that canCancelContentTouches.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Change log from 2.2:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Fixed an obscure bug that causes crashing when the scroll view disappears. Thanks Optimo for discovering.&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-7754587954469999500?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/7754587954469999500/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/09/quickscroll-22-should-be-available-on.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/7754587954469999500'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/7754587954469999500'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/09/quickscroll-22-should-be-available-on.html' title='QuickScroll 2.2a should be available on Cydia soon.'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-1249497968598325838</id><published>2009-09-18T19:39:00.007+08:00</published><updated>2009-09-19T15:51:47.769+08:00</updated><title type='text'>Porting the SDK's gdb for 3.1</title><content type='html'>The gdb on Cydia currently doesn't work on 3.1 because of the new Mach-O format. We could compile gdb from source (which I've failed to do so), wait for someone else to compile from source (&lt;del&gt;which I'm still waiting&lt;/del&gt;), or just use the gdb in the SDK.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;strong&gt;Update:&lt;/strong&gt; saurik has updated the gdb package that works in 3.1, which will be available tomorrow. You can download it now from &lt;a href="http://apt.saurik.com/debs/gdb_1128-8_iphoneos-arm.deb"&gt;http://apt.saurik.com/debs/gdb_1128-8_iphoneos-arm.deb&lt;/a&gt;.&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;The SDK's gdb is in &lt;tt&gt;/Developer/Platforms/iPhoneOS.platform/Developer/usr/libexec/gdb/gdb-arm-apple-darwin&lt;/tt&gt;. While you can run it directly on your Mac, it is in fact a fat binary with 3 architectures:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;strong&gt;file gdb-arm-apple-darwin &lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;gdb-arm-apple-darwin: Mach-O universal binary with 3 architectures&lt;br /&gt;gdb-arm-apple-darwin (for architecture ppc): Mach-O executable ppc&lt;br /&gt;gdb-arm-apple-darwin (for architecture i386): Mach-O executable i386&lt;br /&gt;gdb-arm-apple-darwin (for architecture armv5): Mach-O executable arm&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;The ARMv5 portion is what we want. But this gdb is useless to run on the iPhoneOS because it lacks all the essential entitlements. While entitlements can be inserted using ldid, there is a limitation needs to be worked-around: ldid doesn't support the &lt;tt&gt;armv5&lt;/tt&gt; architecture. We have to modify the source code of ldid to allow it:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;@@ -557,6 +557,7 @@&lt;br /&gt;                     case 12: switch (framework-&gt;cpusubtype) {&lt;br /&gt;                         case 0: arch = "arm"; break;&lt;br /&gt;                         case 6: arch = "armv6"; break;&lt;br /&gt;+                        case 7: arch = "armv5"; break;&lt;br /&gt;                         default: arch = NULL; break;&lt;br /&gt;                     } break;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;(I have also &lt;tt&gt;lipo -thin&lt;/tt&gt;-ed the gdb before ldid-ing to make everything smooth.) After applying this patch, the ldid should recognize armv5 correctly. Now, save this portion of text as an XML file (e.g. gdb.xml):&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&amp;lt;!DOCTYPE plist PUBLIC &amp;quot;-//Apple//DTD PLIST 1.0//EN&amp;quot; &amp;quot;http://www.apple.com/DTDs/PropertyList-1.0.dtd&amp;quot;&amp;gt;&lt;br /&gt;&amp;lt;plist version=&amp;quot;1.0&amp;quot;&amp;gt;&lt;br /&gt;&amp;lt;dict&amp;gt;&lt;br /&gt; &amp;lt;key&amp;gt;com.apple.springboard.debugapplications&amp;lt;/key&amp;gt;&lt;br /&gt; &amp;lt;true/&amp;gt;&lt;br /&gt; &amp;lt;key&amp;gt;get-task-allow&amp;lt;/key&amp;gt;&lt;br /&gt; &amp;lt;true/&amp;gt;&lt;br /&gt; &amp;lt;key&amp;gt;task_for_pid-allow&amp;lt;/key&amp;gt;&lt;br /&gt; &amp;lt;true/&amp;gt;&lt;br /&gt; &amp;lt;key&amp;gt;run-unsigned-code&amp;lt;/key&amp;gt;&lt;br /&gt; &amp;lt;true/&amp;gt;&lt;br /&gt;&amp;lt;/dict&amp;gt;&lt;br /&gt;&amp;lt;/plist&amp;gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;and then run:&lt;br /&gt;&lt;blockquote&gt;&lt;strong&gt;ldid -Sgdb.xml gdb&lt;/strong&gt;&lt;/blockquote&gt;&lt;br /&gt;, and the gdb should now be completely usable on the iPhoneOS.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-1249497968598325838?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/1249497968598325838/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/09/porting-sdks-gdb-for-31.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/1249497968598325838'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/1249497968598325838'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/09/porting-sdks-gdb-for-31.html' title='Porting the SDK&apos;s gdb for 3.1'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-1283261016936717849</id><published>2009-09-17T02:13:00.002+08:00</published><updated>2009-09-17T02:18:25.820+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='iKeyEx'/><title type='text'>iKeyEx 0.1-99j released, now works in 3.1</title><content type='html'>Download: &lt;a href="http://code.google.com/p/networkpx/downloads/detail?name=hk.kennytm.iKeyEx3-0.1-99j.deb"&gt; http://code.google.com/p/networkpx/downloads/detail?name=hk.kennytm.iKeyEx3-0.1-99j.deb&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This version is an emergency release to make it work in 3.1 (r497, r498). Along with it there are also these changes:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Fixed a crash when uninstalling the Chinese Phrase Tables package (r491)&lt;/li&gt;&lt;li&gt;Fixed a crash when phrases longer than 2 characters are processed (r499)&lt;/li&gt;&lt;li&gt;Fixed a bug in characters sorting, that the sorted array is incorrect (r499).&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-1283261016936717849?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/1283261016936717849/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/09/ikeyex-01-99j-released-now-works-in-31.html#comment-form' title='19 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/1283261016936717849'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/1283261016936717849'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/09/ikeyex-01-99j-released-now-works-in-31.html' title='iKeyEx 0.1-99j released, now works in 3.1'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>19</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-4389456618901825085</id><published>2009-09-16T03:19:00.004+08:00</published><updated>2009-09-16T03:24:25.238+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='QuickScroll'/><title type='text'>QuickScroll 2.1a.</title><content type='html'>Download: &lt;a href="http://code.google.com/p/networkpx/downloads/detail?name=hk.kennytm.quickscroll2-0.2-1a.deb"&gt; http://code.google.com/p/networkpx/downloads/detail?name=hk.kennytm.quickscroll2-0.2-1a.deb&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;New features:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;QuickScroll can be disabled for each particular app, including SpringBoard.&lt;/li&gt;&lt;li&gt;Activate by scrolling. (This is off by default since you can't have smooth scrolling with QuickScroll. Oh you have 3GS? Forget I what say then...)&lt;/li&gt;&lt;li&gt;New icon design by Sagitt.&lt;/li&gt;&lt;li&gt;Localizations.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;After this release all features will be frozen. That is, no new features will be accepted, no matter how ingenious it is. (Ya know, this thing gotta be pushed out some day). Only bug fix and new localizations will be allowed for 2.2 (the public version).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-4389456618901825085?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/4389456618901825085/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/09/quickscroll-21a.html#comment-form' title='14 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/4389456618901825085'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/4389456618901825085'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/09/quickscroll-21a.html' title='QuickScroll 2.1a.'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>14</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-7563169722064765858</id><published>2009-09-15T02:26:00.002+08:00</published><updated>2009-09-15T02:31:35.691+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='QuickScroll'/><title type='text'>QuickScroll 2.1.</title><content type='html'>Download: &lt;a href="http://code.google.com/p/networkpx/downloads/detail?name=hk.kennytm.quickscroll2-0.2-1.deb"&gt; http://code.google.com/p/networkpx/downloads/detail?name=hk.kennytm.quickscroll2-0.2-1.deb&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Changes:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The scrollers should now be easier to grab and move around.&lt;/li&gt;&lt;li&gt;Duration now really defaults to 2 seconds on first install. Thanks fusen for noticing.&lt;/li&gt;&lt;li&gt;Scrollbars can be chosen to jump on spot instead of next page. Thanks Sagitt for suggestion.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;(If there're no other bugs I'll submit this version to BigBoss.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-7563169722064765858?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/7563169722064765858/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/09/quickscroll-21.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/7563169722064765858'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/7563169722064765858'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/09/quickscroll-21.html' title='QuickScroll 2.1.'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-440558216415542657</id><published>2009-09-14T01:37:00.002+08:00</published><updated>2009-09-14T02:44:32.986+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='QuickScroll'/><title type='text'>QuickScroll 2 released</title><content type='html'>With a 333% size increase*, &lt;a href="http://code.google.com/p/networkpx/downloads/detail?name=hk.kennytm.quickscroll2-0.2.deb "&gt;QuickScroll 2&lt;/a&gt; is released to improve the scrolling experience.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;QuickScroll 2 now introduces scrollbars, which is the default. &lt;br /&gt;&lt;img src="http://x28.xanga.com/ad2f737a06632254588213/w202389898.png" /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Besides PDF files, scroll views that explicitly allowed for paging can also be targeted.&lt;br /&gt;&lt;img src="http://xcd.xanga.com/3b9f564343133254591514/w202392728.png" /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;The old scroller is still accessible, but you can now move it around (and occupies much less space).&lt;br /&gt;&lt;img src="http://x94.xanga.com/c0cf777a26635254588214/w202389899.png" /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;(To jump to a page, tap the 123 icon at the lower right corner in scroll bar mode, or tap the ← arrow button in scroller dialog mode.)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;These configuration can be set in Settings.&lt;br /&gt;&lt;img src="http://xdd.xanga.com/4d6f434039033254588215/w202389900.png" /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;As you can see, there are 2 more gestures you can choose. The two-finger tap should allow you activate QuickScroll in a table view easier.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;I've eliminated the close button. The scrollers will disappear in 2 seconds of inactivity.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;QuickScroll's scrollers are now actually a subview of the scrolling view, while in the 1st version it is an alert box. This change allows QuickScroll to be used in very high-level windows like those in SBSettings and GriP.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;I don't know how to localize PreferenceLoader entries yet. So no localizations in this version, sorry.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;*: 24 KiB &amp;rarr; 104 KiB on disk.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-440558216415542657?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/440558216415542657/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/09/quickscroll-2-released.html#comment-form' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/440558216415542657'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/440558216415542657'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/09/quickscroll-2-released.html' title='QuickScroll 2 released'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-1568093063422013368</id><published>2009-09-11T22:22:00.002+08:00</published><updated>2009-09-11T22:30:06.744+08:00</updated><title type='text'>Get UIView hierarchy, take 3.</title><content type='html'>The &lt;a href="http://networkpx.blogspot.com/2009/08/easier-way-to-get-uiview-hierarchy.html"&gt;previous post&lt;/a&gt; about dumping UIView hierarchy is actually over-complicated. Actually all you need is one command (in gdb):&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;po [[[UIApplication sharedApplication] keyWindow] scriptingInfoWithChildren]&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;The result will be very verbose, make sure your terminal has enough scrollback.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-1568093063422013368?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/1568093063422013368/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/09/get-uiview-hierarchy-take-3.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/1568093063422013368'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/1568093063422013368'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/09/get-uiview-hierarchy-take-3.html' title='Get UIView hierarchy, take 3.'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-9079306337410427447</id><published>2009-09-10T03:11:00.003+08:00</published><updated>2009-09-10T03:28:42.606+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='iKeyEx'/><title type='text'>iKeyEx 0.1-99i released.</title><content type='html'>Download = &lt;a href="http://code.google.com/p/networkpx/downloads/detail?name=hk.kennytm.iKeyEx3-0.1-99i.deb"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Changes:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Fixed issue &lt;a href="http://code.google.com/p/networkpx/issues/detail?id=313"&gt;313&lt;/a&gt;. In an alt (numbers) plane, pressing the space key will go back to the main (alphabets) plane.&lt;/li&gt;&lt;li&gt;Typing the apostrophe (') in the main plane no longer auto-switch to the alt plane.&lt;/li&gt;&lt;li&gt;Fixed issue &lt;a href="http://code.google.com/p/networkpx/issues/detail?id=312"&gt;312&lt;/a&gt;, and many other auto-shift related quirks.&lt;/li&gt;&lt;li&gt;.cin IME:&lt;ul&gt;&lt;li&gt;Number of candidates is limited to avoid near-infinite loop. 64.0 candidates should be enough for everyone.&lt;/li&gt;&lt;li&gt;Multi-radical continuation works again.&lt;/li&gt;&lt;li&gt;Fixed cases where blank candidates appear.&lt;/li&gt;&lt;li&gt;Candidate searching now operates in serial for reliability. You may experience some degrade in performance.&lt;/li&gt;&lt;li&gt;A progress indicator is added when the Patricia tree dump for the IME was first generated. This is essential for some huge IME like 輕鬆輸入法, which takes nearly 2 minutes for the first launch.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;(Chinese Users: 倉頡輸入法及額外字頻表及詞庫亦更新至 0.2-1 版，這與 0.2-0 版內容上其實沒分別，只是製作 deb 時改用了 gnutar，從而避免因含非 ASCII 檔名而導致安裝失敗。若果你正在使用這些軟件，則不用更新。)&lt;br /&gt;&lt;br /&gt;By the way, if you find any bugs, please report at &lt;a href="http://code.google.com/p/networkpx/issues/list"&gt;Issues&lt;/a&gt; in the project page. If you leave a comment here or the wiki I can't guarantee I can dig and fix that.&lt;br /&gt;&lt;br /&gt;&lt;em&gt;Preemptive Warning&lt;/em&gt;: Comments not related to this content will be ignored.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-9079306337410427447?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/9079306337410427447/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/09/ikeyex-01-99i-released.html#comment-form' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/9079306337410427447'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/9079306337410427447'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/09/ikeyex-01-99i-released.html' title='iKeyEx 0.1-99i released.'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-6834417620115194651</id><published>2009-09-07T02:17:00.006+08:00</published><updated>2009-09-11T16:44:22.109+08:00</updated><title type='text'>Introducing Subjective-C, an objc_msgSend[_[st|fp]ret]? logger.</title><content type='html'>Time ago I &lt;a href="http://code.google.com/p/networkpx/source/browse/etc/objc_msgSend_hook.mm?r=472"&gt;logged calls&lt;/a&gt; to objc_msgSend to understand how to construct UIKBKeyboards. But that logger is known to cause problems due to asserting the arguments use less than 1024 bytes. I needed to log calls again for &lt;a href="http://code.google.com/p/networkpx/issues/detail?id=312"&gt;issue 312&lt;/a&gt;, but the old buggy behavior leads me to rewriting it more reliably.&lt;br /&gt;&lt;br /&gt;The result is the dynamic library called &lt;a href="http://code.google.com/p/networkpx/downloads/detail?name=libsubjc.dylib "&gt;Subjective-C&lt;/a&gt;. It has the following new features:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Stack-safe. No arguments will be lost due to this logger.&lt;/li&gt;&lt;li&gt;Call tree construction.&lt;/li&gt;&lt;li&gt;Filtering.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;along with the old features:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Print and format all arguments, and the return value.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Note:&lt;ul&gt;&lt;li&gt;Due to licensing, only the ARM version is released, although the x86 version works perfectly.&lt;/li&gt;&lt;li&gt;If your product depends on Subjective-C (why?), please note that it is GPLv3.&lt;/li&gt;&lt;li&gt;(No, it won't help even if I BSD everything.)&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Sample output&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; +[UIScroller _registerForNotifications]&lt;br /&gt; +[NSString alloc] {&lt;br /&gt;  +[NSString allocWithZone:] (0x0)&lt;br /&gt; }&lt;br /&gt; +[NSBundle mainBundle] {&lt;br /&gt;  -[NSRecursiveLock lock] &lt;0x1007540&gt;&lt;br /&gt;  -[NSRecursiveLock unlock] &lt;0x1007540&gt;&lt;br /&gt; } = &amp;lt;NSBundle 0x100db50&gt;&lt;br /&gt; -[NSBundle bundleIdentifier] &lt;0x100db50&gt; {&lt;br /&gt;  -[NSBundle infoDictionary] &lt;0x100db50&gt; {&lt;br /&gt;   -[NSBundle _cfBundle] &lt;0x100db50&gt; = 0x1009d60&lt;br /&gt;  } = &amp;lt;NSCFDictionary 0x100af10&gt;&lt;br /&gt;  -[NSCFDictionary objectForKey:] &lt;0x100af10&gt; (@"CFBundleIdentifier") = @"com.yourcompany.Untitled4"&lt;br /&gt; } = @"com.yourcompany.Untitled4"&lt;br /&gt; -[NSPlaceholderString initWithFormat:] &lt;0x100cf70&gt; (@"%@.UIKit.migserver") {&lt;br /&gt;  -[NSPlaceholderString initWithFormat:locale:arguments:] &lt;0x100cf70&gt; (@"%@.UIKit.migserver", nil, "∞≠") {&lt;br /&gt;   -[NSCFString respondsToSelector:] &lt;0x100adb0&gt; (@selector(descriptionWithLocale:)) {&lt;br /&gt;    -[NSCFString class] &lt;0x100adb0&gt; = NSCFString&lt;br /&gt;    +[NSCFString resolveInstanceMethod:] (@selector(descriptionWithLocale:)) = NO&lt;br /&gt;   } = NO&lt;br /&gt;   -[NSCFString description] &lt;0x100adb0&gt; = /*self*/ @"com.yourcompany.Untitled4"&lt;br /&gt;  } = @"com.yourcompany.Untitled4.UIKit.migserver"&lt;br /&gt; } = @"com.yourcompany.Untitled4.UIKit.migserver"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;API&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;You can find the header file in &lt;a href="http://code.google.com/p/networkpx/source/browse/etc/subjc.h"&gt;subjc.h&lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;Most of the case you just need to call two functions:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;void &lt;strong&gt;SubjC_start&lt;/strong&gt;(FILE* f, size_t maximum_depth, bool print_arguments, bool print_return_value)&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Starts logging all objective-C calls. The result will be written to the file &lt;em&gt;f&lt;/em&gt;, up to a maximum call-tree depth &lt;em&gt;maximum_depth&lt;/em&gt;. You may use the boolean parameters &lt;em&gt;print_arguments&lt;/em&gt; and &lt;em&gt;print_return_value&lt;/em&gt; to control whether to format the arguments and return values. Not doing so may save some time.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;void &lt;strong&gt;SubjC_end&lt;/strong&gt;();&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Stops logging. This function must be called at the same level as &lt;tt&gt;SubjC_start&lt;/tt&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;The SubjC_initialize() function does the initialization things. It will be called automatically in SubjC_start if not done, so you don't need to explicitly call it.&lt;br /&gt;&lt;br /&gt;The rest are to control whether a (sub)message can be logged. If a message is &lt;em&gt;filtered&lt;/em&gt;, all calls &lt;em&gt;spawned by &lt;br /&gt;this message&lt;/em&gt; will not be logged. For example, if the selector &lt;tt&gt;copy&lt;/tt&gt; is filtered, then in the log you will only see&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;-[XXSomeClass copy] &amp;lt;0xfedcba98&amp;gt; = &amp;lt;XXSomeClass 0x12345678&amp;gt;&lt;/pre&gt;&lt;/blockquote&gt;instead of &lt;blockquote&gt;&lt;pre&gt;-[XXSomeClass copy] = {&lt;br /&gt; -[XXSomeClass copyWithZone:] &amp;lt;0xfedcba98&amp;gt; (0x0) = &amp;lt;XXSomeClass 0x12345678&amp;gt;&lt;br /&gt;} = &amp;lt;XXSomeClass 0x12345678&amp;gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Known issues&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Subjective-C is not thread-safe. &lt;del&gt;I repeat: Subjective-C is not thread-safe. If there are ≥1 threads that uses Objective-C during logging you're almost surely doomed to crash.&lt;/del&gt; OK it won't crash now by changing the global lr stack to thread-local, but it's still not completely thread-safe.&lt;/li&gt;&lt;li&gt;Variadic arguments can never be logged.&lt;/li&gt;&lt;li&gt;+initialize messages cannot be logged. This is because Subjective-C cannot work if the class is not initialized, so it implicitly initialize the class before logging.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;How it works&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;All Objective-C calls (except the manually cached ones) will go through objc_msgSend, objc_msgSend_stret, and in x86, objc_msgSend_fpret. Therefore, if we replace these functions with our custom one the every message can be logged. &lt;br /&gt;&lt;br /&gt;The tricky part is to call the original function after logging is finished. GCC has __builtin_apply_args and friends to construct the calls, but it assumes you know the maximum bytes of the arguments, because the approach taken by these is to &lt;em&gt;copy&lt;/em&gt; the content of stack. This leads to the buggy behavior in the old logger.&lt;br /&gt;&lt;br /&gt;To avoid this, the new logger was written in assembly. The approach (and the name) was inspired by saurik's &lt;a href="http://svn.saurik.com/repos/menes/trunk/aspectivec/"&gt;Aspective-C&lt;/a&gt; (thanks for informing this work). In the new logger, every action before calling the original function was done without modifying the stack pointer and the content above it, nor the registers.&lt;br /&gt;&lt;br /&gt;That means, in ARM, the registers r0-r3 cannot be modified, push/pop cannot be used, and the only free register is r12. Fortunately, heap memory can still be accessed, and well-defined functions will not affect anything except r0-r3, r12 and lr, so the only necessary step to perform is&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Load the address of an array of 32-bit integers&lt;/li&gt;&lt;li&gt;Store r0-r3 in there&lt;/li&gt;&lt;li&gt;Call any functions we like&lt;/li&gt;&lt;li&gt;Load the address of that array again&lt;/li&gt;&lt;li&gt;Restore r0-r3 from there.&lt;/li&gt;&lt;li&gt;Call original objc_msgSend&lt;/li&gt;&lt;li&gt;Print the returned value and return.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;But to return, the link register (lr) need to persist. And it needs to persist throughout the whole replaced function, which in the middle a self-call may happen. This means the lr must be stored on a stack:&lt;ul&gt;&lt;li&gt;Load the address of an array of 32-bit integers&lt;/li&gt;&lt;li&gt;Store r0-r3 in there&lt;/li&gt;&lt;li style="color:red;"&gt;Push lr onto a custom stack&lt;/li&gt;&lt;li&gt;Call any functions we like&lt;/li&gt;&lt;li&gt;Load the address of that array again&lt;/li&gt;&lt;li&gt;Restore r0-r3 from there.&lt;/li&gt;&lt;li&gt;Call original objc_msgSend&lt;/li&gt;&lt;li style="color:red;"&gt;Pop lr from the custom stack&lt;/li&gt;&lt;li&gt;Print the returned value and return.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;The situation is easier on x86. Every argument, and the return address must be on the stack. Therefore the "Store r0-r3" steps can be ignored. Nevertheless, we need to replace the return address to ensure the original objc_msgSend return to our place, so the custom stack is still needed.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Compiling Subjective-C&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;To compile Subjective-C you need the following:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;g++&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.boost.org/"&gt;Boost C++ library&lt;/a&gt; (for unordered_set)&lt;/li&gt;&lt;li&gt;Source code for the whole &lt;a href="http://code.google.com/p/networkpx/source/browse/#svn/trunk/hk.kennytm.Peace"&gt;hk.kennytm.Peace&lt;/a&gt; subproject (for argument formatting).&lt;/li&gt;&lt;li&gt;&lt;a href="http://unsanity.com/haxies/ape/sdk"&gt;APELite&lt;/a&gt;, if you compile for x86.&lt;/li&gt;&lt;li&gt;MobileSubstrate, if you compile for ARM.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://code.google.com/p/networkpx/source/browse/etc/subjc.mf"&gt;subjc.mf&lt;/a&gt; contains the Makefile for ARM, and &lt;a href="http://code.google.com/p/networkpx/source/browse/etc/subjc.x86"&gt;subjc.x86&lt;/a&gt; for x86.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-6834417620115194651?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/6834417620115194651/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/09/introducing-subjective-c.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/6834417620115194651'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/6834417620115194651'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/09/introducing-subjective-c.html' title='Introducing Subjective-C, an objc_msgSend[_[st|fp]ret]? logger.'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-4425906157687898093</id><published>2009-09-02T03:31:00.004+08:00</published><updated>2009-09-02T03:46:54.610+08:00</updated><title type='text'>stmXX</title><content type='html'>&lt;pre&gt;&lt;br /&gt;static int rx_reserve[8];&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt; __asm__(" mov r1, #1\n"&lt;br /&gt;   " mov r2, #2\n"&lt;br /&gt;   " mov r3, #3\n"&lt;br /&gt;   " ldr r0, (reserve)\n"&lt;br /&gt;   " mov r4, r0\n"&lt;br /&gt;   " ????? r0!, {r1-r3}\n"&lt;br /&gt;   " str r0, [r4, #16]\n"&lt;br /&gt;   " b after_data\n"&lt;br /&gt;   "reserve:\n"&lt;br /&gt;   " .long _rx_reserve+12\n"&lt;br /&gt;   "after_data:\n");&lt;br /&gt; &lt;br /&gt; printf("%d %d %d [%d] %d %d %d;\ndelta = %d\n",&lt;br /&gt;     rx_reserve[0], rx_reserve[1], rx_reserve[2], rx_reserve[3], rx_reserve[4], rx_reserve[5], rx_reserve[6],&lt;br /&gt;     rx_reserve[7]-(int)(rx_reserve+3) );&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tr&gt;&lt;th&gt;?????&lt;/th&gt;&lt;th&gt;Result&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;stmia&lt;/td&gt;&lt;td&gt;0 0 0 [1] 2 3 &lt;u&gt;0&lt;/u&gt;;&lt;br /&gt;delta = 12&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;stmib&lt;/td&gt;&lt;td&gt;0 0 0 [0] 1 2 &lt;u&gt;3&lt;/u&gt;;&lt;br /&gt;delta = 12&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;stmda&lt;/td&gt;&lt;td&gt;&lt;u&gt;0&lt;/u&gt; 1 2 [3] 0 0 0;&lt;br /&gt;delta = -12&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;stmdb&lt;/td&gt;&lt;td&gt;&lt;u&gt;1&lt;/u&gt; 2 3 [0] 0 0 0;&lt;br /&gt;delta = -12&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-4425906157687898093?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/4425906157687898093/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/09/stmxx.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/4425906157687898093'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/4425906157687898093'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/09/stmxx.html' title='stmXX'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-3708886325837082115</id><published>2009-09-01T06:57:00.002+08:00</published><updated>2009-09-01T07:37:19.947+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='5RowQWERTY'/><category scheme='http://www.blogger.com/atom/ns#' term='iKeyEx'/><title type='text'>iKeyEx &amp; 5-Row QWERTY 0.1-99h are released</title><content type='html'>Downloads can be found in &lt;a href="http://code.google.com/p/networkpx/downloads/list"&gt;here&lt;/a&gt; as usual. &lt;br /&gt;&lt;br /&gt;Changes from "g" are:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;You can now long-press control keys (left, right, etc) to repeat actions.&lt;/li&gt;&lt;li&gt;ANSI and X11 apps for control keys are now correctly detected.&lt;/li&gt;&lt;li&gt;The config file is moved to ~/Library/Keyboard/iKeyEx::config.plist.  This allows the config to be preserved even after firmware upgrade. (Permission problems will also be fixed during installation.)&lt;/li&gt;&lt;li&gt;PSBundle for layouts and IMEs. Normal users can find them in Settings &amp;rarr; iKeyEx &amp;rarr; Customize.&lt;/li&gt;&lt;li&gt;In the delete cache page, the total file size of the cache entry will be reported.&lt;/li&gt;&lt;li&gt;Candidate calculation in .cin IMEs now actually runs in background.&lt;/li&gt;&lt;li&gt;Associated phrases (aka Completion) can be disabled.&lt;/li&gt;&lt;li&gt;iKeyEx-KBMan now registers input modes correctly without causing crashes. Also it now purges layout cache correctly.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;The "h" version of iKeyEx is considered a release candidate. I'll try to get it to BigBoss's beta repo if no major bug is found.&lt;br /&gt;&lt;br /&gt;Many of the changes in "g" and "h" are to prepare for the 5 Row QWERTY layout. Of course, the major change for 5 Row QWERTY is it works on 3.0, but even compared with 0.1-9b, there are a few points to need to notice:&lt;ol&gt;&lt;li&gt;You'll find that the Tab, Esc, Page Up keys etc become words instead of symbols. This is because, with the system fonts all the previous symbols cannot be rendered. For consistency I just change them all into words.&lt;/li&gt;&lt;li&gt;The "Autocorrection" part of the old pref bundle is now handled by Mix &amp; Match.&lt;/li&gt;&lt;li&gt;Sometimes your customization won't take effect. Try to Delete cache if that happens.&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;There are no modifications other than these.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-3708886325837082115?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/3708886325837082115/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/09/ikeyex-5-row-qwerty-01-99h-are-released.html#comment-form' title='22 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/3708886325837082115'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/3708886325837082115'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/09/ikeyex-5-row-qwerty-01-99h-are-released.html' title='iKeyEx &amp; 5-Row QWERTY 0.1-99h are released'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>22</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-6051210554369899600</id><published>2009-08-30T21:36:00.002+08:00</published><updated>2009-08-30T21:42:48.930+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='iKeyEx'/><title type='text'>iKeyEx 0.1-99g is released</title><content type='html'>&lt;a href="http://networkpx.googlecode.com/files/hk.kennytm.iKeyEx3-0.1-99g.deb"&gt;Download.&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Changelog:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;“Text with traits” is now supported, that means your can add color, change font and text size for each key. However, you still cannot use key with image.&lt;/li&gt;&lt;li&gt;Native control keys support. (Left, right, home, page down, etc.)&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-6051210554369899600?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/6051210554369899600/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/08/ikeyex-01-99g-is-released.html#comment-form' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/6051210554369899600'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/6051210554369899600'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/08/ikeyex-01-99g-is-released.html' title='iKeyEx 0.1-99g is released'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-6413212974175729543</id><published>2009-08-26T05:14:00.004+08:00</published><updated>2009-08-28T03:52:05.080+08:00</updated><title type='text'>Easier way to get UIView hierarchy.</title><content type='html'>Before I documented &lt;a href="http://networkpx.blogspot.com/2009/06/displaying-uiview-hierarchy-in-runtime.html"&gt;how you can obtain the UIView hierarchy in syslog&lt;/a&gt;. It uses custom function, but there is are 2 built-in way to get this.&lt;br /&gt;&lt;br /&gt;The first, standard way is to send a GSEvent type #500 to the application, then the dump will be written to /tmp/UIDump in plist format. You can achieve the same by calling in gdb:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;call (void)[[UIApplication sharedApplication] _dumpUIHierarchy:0]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;When the dump is completed, a Darwin notification "com.apple.UIHierarchyDump.finished" will be posted.&lt;br /&gt;&lt;br /&gt;(You can also take a screenshot with _dumpScreenContents:0 / GSEvent type #501, but the file is in JPEG and pressing Lock+Home isn't that hard...)&lt;br /&gt;&lt;br /&gt;(Note: May fail for AppStore apps due to sandboxing.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-6413212974175729543?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/6413212974175729543/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/08/easier-way-to-get-uiview-hierarchy.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/6413212974175729543'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/6413212974175729543'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/08/easier-way-to-get-uiview-hierarchy.html' title='Easier way to get UIView hierarchy.'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-3500977662955226509</id><published>2009-08-26T02:37:00.003+08:00</published><updated>2009-08-26T03:38:54.029+08:00</updated><title type='text'>GSEvent Recording and Playback in 3.0</title><content type='html'>iPhoneOS has built-in API for application macro since 2.x. (Of course it was never documented.) (And the API was really changed in 3.0 to adopt for multiple recorders.)&lt;br /&gt;&lt;br /&gt;For example, to record everything you've done during the for yourUIApplication:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; recorder = [Recorder new];&lt;br /&gt; &lt;font color="red"&gt;[yourUIApplication _addRecorder:recorder];&lt;/font&gt;&lt;br /&gt; [recorder release];&lt;br /&gt;&lt;/pre &gt;&lt;br /&gt;The command _addRecorder: adds the object to the application's event recorder array. You can remove your recorder at anytime with &lt;br /&gt;&lt;pre&gt;&lt;br /&gt; &lt;font color="red"&gt;[yourUIApplication _removeRecorder:recorder];&lt;/font&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;An event recorder must conform to the informal protocol&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;@protocol UIEventRecorder&lt;br /&gt;-(void)recordApplicationEvent:(NSDictionary*)event;&lt;br /&gt;@end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Here, "event" is a GSEvent converted to a plist using GSEventCreatePlistRepresentation(). You can add the event to an array and save that array for later reference, e.g.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;@interface Recorder : NSObject { NSMutableArray* eventList; } @end&lt;br /&gt;@implementation Recorder&lt;br /&gt;-(id)init { if ((self = [super init])) eventList = [NSMutableArray new]; return self; }&lt;br /&gt;-(void)save { [eventList writeToFile:@"events.plist" atomically:YES]; }&lt;br /&gt;-(void)recordApplicationEvent:(NSDictionary*)event { [eventList addObject:event]; }&lt;br /&gt;@end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Now say you want to play back the events you've previously collected. Just use this code:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;NSArray* eventList = [NSArray arrayWithContentsOfFile:@"events.plist"];&lt;br /&gt;float playbackRate = 1;&lt;br /&gt;[app _playbackEvents:eventList atPlaybackRate:playbackRate messageWhenDone:target withSelector:@selector(done:)];&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The higher the playback rate, the faster the system will run the events. &lt;br /&gt;&lt;br /&gt;When the playback is finished, the "done:" selector will be called for "target". This selector must have a signature of&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;-(void)done:(NSDictionary*)detail;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;the "detail" argument contains exactly 1 key, "UIApplicationEventRecordingDeliveryTimeUserInfoKey", which points to an array of the time the corresponding event happened.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-3500977662955226509?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/3500977662955226509/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/08/gsevent-recording-and-playback-in-30.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/3500977662955226509'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/3500977662955226509'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/08/gsevent-recording-and-playback-in-30.html' title='GSEvent Recording and Playback in 3.0'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-6259509536358104756</id><published>2009-08-25T05:25:00.002+08:00</published><updated>2009-08-25T06:01:35.180+08:00</updated><title type='text'>Decompressing .zip files with iWorkImport.framework.</title><content type='html'>.zip files need to be supported in lots of places on the iPhoneOS. .ipa are zip files, .docx are zip files, .key are zip files. Unfortunately there is no centralized framework or library to handle these zip files. In fact, all Bom.framework, OfficeImport.framework and iWorkImport.framework have their own, private implementation to decompress a .zip file. Out of the three, iWorkImport.framework is the friendliest.&lt;br /&gt;&lt;br /&gt;This example code shows how to open a .zip file and read the content:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://pastebin.com/f16274c11"&gt;http://pastebin.com/f16274c11&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;(Of course, if you write your new application, you &lt;em&gt;should not&lt;/em&gt; unzip like this :) use something documented such as &lt;a href="http://code.google.com/p/ziparchive/"&gt;ziparchive&lt;/a&gt;.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-6259509536358104756?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/6259509536358104756/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/08/decompressing-zip-files-with.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/6259509536358104756'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/6259509536358104756'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/08/decompressing-zip-files-with.html' title='Decompressing .zip files with iWorkImport.framework.'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-3297145721294988847</id><published>2009-08-24T04:01:00.003+08:00</published><updated>2009-08-24T04:48:46.980+08:00</updated><title type='text'>Trivia for Preference Bundles.</title><content type='html'>&lt;h3&gt;1. How to create that red delete button?&lt;/h3&gt;&lt;br /&gt;The red delete button in VPN is in fact very easy to implement. All you need to do is add the following code:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#import &amp;lt;UIKit/UIPreferencesDeleteTableCell.h&amp;gt;&lt;br /&gt;@interface PSDeleteTableCell : UIPreferencesDeleteTableCell @end&lt;br /&gt;@implementation PSDeleteTableCell&lt;br /&gt;-(void)setValueChangedTarget:(id)target action:(SEL)action userInfo:(NSDictionary*)info {&lt;br /&gt; [self setTarget:target];&lt;br /&gt; [self setAction:action];&lt;br /&gt;}&lt;br /&gt;-(UILabel*)titleTextLabel {&lt;br /&gt; UILabel* res = [super titleTextLabel];&lt;br /&gt; res.textColor = [UIColor whiteColor];&lt;br /&gt; return res;&lt;br /&gt;}&lt;br /&gt;@end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;and then in the specifier plist, modify your button as:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;...&lt;br /&gt;{ cell = PSButtonCell;&lt;br /&gt;  action = nukeFromOrbit;&lt;br /&gt;  label = "Nuke from Orbit;&lt;br /&gt;  ...&lt;br /&gt;  &lt;span style="color:red;"&gt;cellClass = PSDeleteTableCell;&lt;/span&gt;&lt;br /&gt;},&lt;br /&gt;...&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The result is:&lt;br /&gt;&lt;p&gt;&lt;img src="http://x9e.xanga.com/5e9f4776d9532252938584/w200951074.png" /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;2. PSEditableListController&lt;/h3&gt;&lt;br /&gt;Normally list controllers inherit from the PSListController, but you can make a class inherit from PSEditableListController so that it becomes... editable! Actually, more like deletable. There will be an extra Edit/Done button on the top right hand corner, pressing it will reveal the deletion control. If you actually delete a cell, the corresponding specifier's &lt;code&gt; deletionAction&lt;/code&gt; will be called.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;3. A list of editing panes&lt;/h3&gt;&lt;br /&gt;There are several editing panes in Preferences.framework and .app. To use those panes, just use the specifier plist&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;{ cell = PSLinkCell;&lt;br /&gt;  detail = PSDetailController;&lt;br /&gt;  pane = &lt;span style="color:red;"&gt;PaneName&lt;/span&gt;;&lt;br /&gt;  ... }&lt;/pre&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;PSMultiValueEditingPane (Include just a PSSegmentCell, useless by itself.)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;PSTextEditingPane (A pane containing a text field and a keyboard.)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;RegulatoryPane (A static image showing the device is FCC approved and in other countries as well.)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;LegalMessagePane&lt;/li&gt;&lt;br /&gt;&lt;li&gt;TimeZonePane (Time zone selector. The returned value doesn't contain just time zone, but also city location.)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;RingtonePane (Note that the ringtone will be played when selected.)&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-3297145721294988847?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/3297145721294988847/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/08/trivia-for-preference-bundles.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/3297145721294988847'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/3297145721294988847'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/08/trivia-for-preference-bundles.html' title='Trivia for Preference Bundles.'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-3065755008680037487</id><published>2009-08-23T01:37:00.002+08:00</published><updated>2009-08-23T03:00:25.280+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='iKeyEx'/><title type='text'>iKeyEx 0.1-99f Released, now supports .cin IME.</title><content type='html'>Download: &lt;a href="http://code.google.com/p/networkpx/downloads/detail?name=hk.kennytm.iKeyEx3-0.1-99f.deb"&gt; here&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Changelog: There were 3 versions in between, "d" was mainly to fix issue 1, "e" was an emergency release to fix a crashing bug on the preferences, and "f" fixes rest of the bugs and improves performance of characters tables.&lt;br /&gt;&lt;br /&gt;&lt;ol type="a" start="4"&gt;&lt;li&gt;&lt;ul&gt;&lt;li&gt;Fixed &lt;a href="http://code.google.com/p/networkpx/issues/detail?id=1"&gt;issue 1&lt;/a&gt;. .cin input manager can be used natively with iKeyEx.&lt;/li&gt;&lt;li&gt;You can now the method to invoke the keyboard chooser, the disable it completely&lt;/li&gt;&lt;li&gt;Fixed a bug that causes crash when a layout.plist using text with traits is encountered. Thanks DB42 (of OpenHebrew) for reporting!&lt;/li&gt;&lt;li&gt;UI for cache removal.&lt;/li&gt;&lt;li&gt;Basic localization (en, es, zh_TW, zh_CN).&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Fixed a bug that may cause preferences to crash. Thanks @mikitomo for reporting!&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;ul&gt;&lt;li&gt;Loading characters table is now much faster (from O(n) to O(1)), that the second time you use a .cin input method will load instantly, instead of need to wait for 1 ~ 3 seconds (at a price of ~200 KiB disk space).&lt;/li&gt;&lt;li&gt;Name for layout.plist keyboard cache are now correctly generated. Thanks DB42 for reporting!&lt;/li&gt;&lt;li&gt;Keyboard list will be properly updated after Mix and match.&lt;/li&gt;&lt;li&gt;The counter in "Delete cache" will be properly updated after a cache entry is removed.&lt;/li&gt;&lt;li&gt;Candidate list computation won't lock up the application forever (at worst case) anymore.&lt;/li&gt;&lt;li&gt;Support for layout.plist on non-default keyboard type is fixed. Thanks DB42 for reporting!&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ol&gt; &lt;br /&gt;&lt;br /&gt;Actually issue 1 was a major reason why the iKeyEx project exists, and now it is finally implemented. The .cin input method is mainly for use in table-based Chinese input method, but it can be used to implement that things too, e.g. the MultiTap method + Text prediction can be made on top of a .cin IME. The technical detail of .cin files and the technology around it can be found &lt;a href="http://code.google.com/p/networkpx/wiki/Chinese_input_method"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The IME support is nowhere versatile. The .cin IME in iKeyEx so far only supports:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Prefix searching (like autocompletion)&lt;/li&gt;&lt;li&gt;Phrase completion&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;In the future it may also support:&lt;br /&gt;&lt;ol start="3"&gt;&lt;li&gt;Key charges&lt;/li&gt;&lt;li&gt;Dynamic dictionaries.&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-3065755008680037487?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/3065755008680037487/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/08/ikeyex-01-99f-released-now-supports-cin.html#comment-form' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/3065755008680037487'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/3065755008680037487'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/08/ikeyex-01-99f-released-now-supports-cin.html' title='iKeyEx 0.1-99f Released, now supports .cin IME.'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-3938700573276506962</id><published>2009-08-12T20:14:00.003+08:00</published><updated>2009-08-26T01:50:44.519+08:00</updated><title type='text'>Embedding a preference bundle, in your app.</title><content type='html'>If you want to use Preferences.framework in your app, you can do it like this. &lt;br /&gt;&lt;br /&gt;First, make a PSListController subclass as you would when creating a Preference Bundle. Then create a subclass of PSRootController, with code like this:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;@interface MyRootController : PSRootController&lt;br /&gt;@end&lt;br /&gt;@implementation MyRootController&lt;br /&gt;-(void)setupRootListForSize:(CGSize)size {&lt;br /&gt; PSSpecifier* spec = [[PSSpecifier alloc] init];&lt;br /&gt; spec.name = @"Anything";&lt;br /&gt; &lt;br /&gt; MyListController* root = [[MyListController alloc] initForContentSize:size];&lt;br /&gt; root.rootController = self;&lt;br /&gt; [root viewWillBecomeVisible:spec];&lt;br /&gt; [spec setTarget:root];&lt;br /&gt; [spec release];&lt;br /&gt; root.parentController = self;&lt;br /&gt; &lt;br /&gt; [self pushController:root];&lt;br /&gt; [root release];&lt;br /&gt;}&lt;br /&gt;@end&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;Finally, in your app's delegate, write these code:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;-(void)applicationDidFinishLaunching:(UIApplication *)application {&lt;br /&gt; window.frame = [UIScreen mainScreen].applicationFrame;&lt;br /&gt;...&lt;br /&gt; MyRootController* rootCtrler = [[MyRootController alloc] initWithTitle:@"Some Title" identifier:@"com.yourcompany.appName"];&lt;br /&gt; [window addSubview:[rootCtrler contentView]];&lt;br /&gt;}&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Why do this? One major reason it that we can now debug the Pref Bundle in Simulator, and speed up development.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-3938700573276506962?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/3938700573276506962/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/08/embedding-preference-bundle-in-your-app.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/3938700573276506962'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/3938700573276506962'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/08/embedding-preference-bundle-in-your-app.html' title='Embedding a preference bundle, in your app.'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-7757723035305001735</id><published>2009-08-12T17:09:00.003+08:00</published><updated>2009-08-12T18:22:07.811+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='QuickScroll'/><category scheme='http://www.blogger.com/atom/ns#' term='iKeyEx'/><title type='text'>iKeyEx 0.1-99c and QuickScroll 0.1-12d released</title><content type='html'>&lt;a href="http://code.google.com/p/networkpx/downloads/detail?name=hk.kennytm.iKeyEx3-0.1-99c.deb"&gt;iKeyEx 0.1-99c&lt;/a&gt; was released, changes were:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Fixed a silly bug causing autocorrection not working for internal input modes.&lt;/li&gt;&lt;li&gt;nlist nows checks for N_ARM_THUMB_DEF just for safety. Probably make it works for 3GS, probably not.&lt;/li&gt;&lt;li&gt;Input modes won't suddenly "reset" now.&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://code.google.com/p/networkpx/downloads/detail?name=hk.kennytm.quickscroll-0.1-12d.deb "&gt;QuickScroll 0.1-12d&lt;/a&gt; (@r437) fixed a bug where you could scroll horizontally (and actually, vertically too) one pixel too far. Also, it now synchronizes when content size change (e.g. additional content of a web page is loaded, or orientation is changed).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-7757723035305001735?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/7757723035305001735/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/08/ikeyex-01-99c-and-quickscroll-01-12d.html#comment-form' title='20 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/7757723035305001735'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/7757723035305001735'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/08/ikeyex-01-99c-and-quickscroll-01-12d.html' title='iKeyEx 0.1-99c and QuickScroll 0.1-12d released'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>20</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-4232936584863630435</id><published>2009-08-12T03:21:00.003+08:00</published><updated>2009-08-12T03:39:21.072+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='QuickScroll'/><title type='text'>QuickScroll 0.1-12c released (bug fixes)</title><content type='html'>QuickScroll 0.1-12c was released. The changes include:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Can scroll to the top in MobileNotes now.&lt;/li&gt;&lt;li&gt;Now the triple tap will iterate all touches, eliminating any possibility that a triple tap (that ought to be caught) is missed.&lt;/li&gt;&lt;li&gt;QuickScroll will be suppressed on non-scrollable views.&lt;/li&gt;&lt;li&gt;QuickScroll (PDF paging) will be suppressed on PDF files with 0 pages (usually those incomplete files).&lt;/li&gt;&lt;li&gt;Japanese localization.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;(And the dylib size drained down from 20,000 bytes to 19,968 bytes :( )&lt;br /&gt;&lt;br /&gt;0.1-12c was submitted to BigBoss, so it should appear in a few days. Those who can't wait can &lt;a href="http://code.google.com/p/networkpx/downloads/detail?name=hk.kennytm.quickscroll-0.1-12c.deb"&gt;download from here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;hr /&gt;&lt;br /&gt;&lt;br /&gt;Meanwhile I want to explain one decision. Why triple tap? My initial intension was three-finger touch, but I sometimes hold the device with one hand and the other occupied, so any multitouch ideas are ruled out. But how about, like, triple-tapping the home button? This won't work either, as it is possible that &lt;em&gt;two&lt;/em&gt; web views appear on screen simultaneously. This excluded all solutions not using the screen, e.g. using the home/lock buttons, shaking the device, etc. &lt;br /&gt;&lt;br /&gt;&lt;hr /&gt;&lt;br /&gt;&lt;br /&gt;If you have installed iKeyEx 0.1-99b (make sure you're using 0.1-99b) and experienced Crash and not using 3GS please email me &lt;a href="kennytm@gmail.com"&gt;kennytm@gmail.com&lt;/a&gt;, preferably with a crash log (and syslog if possible).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-4232936584863630435?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/4232936584863630435/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/08/quickscroll-01-12c-released-bug-fixes.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/4232936584863630435'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/4232936584863630435'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/08/quickscroll-01-12c-released-bug-fixes.html' title='QuickScroll 0.1-12c released (bug fixes)'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-8158329325639017748</id><published>2009-08-11T02:28:00.007+08:00</published><updated>2009-08-11T03:28:36.138+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='QuickScroll'/><title type='text'>QuickScroll 0.1-12b released, supports PDF paging and activating from anywhere</title><content type='html'>&lt;a href="http://code.google.com/p/networkpx/downloads/detail?name=hk.kennytm.quickscroll-0.1-12b.deb "&gt;Download is here&lt;/a&gt;, as usual. The seventy people who have installed 0.1-12a should also upgrade for a correct offset calculation in MobileSafari.&lt;br /&gt;&lt;hr /&gt;&lt;br /&gt;Now QuickScroll becomes a 1.5-day project, so there are much more features introduced.&lt;br /&gt;&lt;br /&gt;Changes:&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Activate QuickScroll from anywhere, like web pages, long text views, tables, MobileTerminal, SpringBoards, just anywhere you can scroll. (Blame MobileSafari for requiring me to introduce this.)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Jump to any page in a PDF file. &lt;/li&gt;&lt;br /&gt;&lt;li&gt;Fixed from 0.1-12: Rotating from portrait to landscape position no longer makes the "Close" button unreachable.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Modified: The alert box is now smaller.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Language support for English, Spanish, Italian (thanks Sagitt for a few translations) and Chinese (T+S).&lt;/li&gt; &lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="http://xb0.xanga.com/38cf9b0046536251796686/w199954674.png" /&gt; &lt;img src="http://xe1.xanga.com/efff640a09634251796690/w199954677.png" /&gt; &lt;img src="http://x39.xanga.com/1f5f960056437251796692/w199954679.png" /&gt; &lt;img src="http://x9c.xanga.com/facf970409037251796695/w199954680.png" /&gt; &lt;img src="http://x07.xanga.com/f94f700727d35251797650/w199955452.png" /&gt;&lt;br /&gt;&lt;br /&gt;This version should be stable enough and I think no more features are needed (besides more localizations). The very same package shall appear in Cydia repo soon if I receive no bug reports by tomorrow (14:00 at GMT+8).&lt;br /&gt;&lt;hr /&gt;&lt;br /&gt;P.S. The dylib is exactly 20,000 bytes.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-8158329325639017748?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/8158329325639017748/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/08/quickscroll-01-12b-released-supports.html#comment-form' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/8158329325639017748'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/8158329325639017748'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/08/quickscroll-01-12b-released-supports.html' title='QuickScroll 0.1-12b released, supports PDF paging and activating from anywhere'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-1719385646731716960</id><published>2009-08-10T05:20:00.002+08:00</published><updated>2009-08-10T05:23:13.721+08:00</updated><title type='text'>QuickScroll 0.1-12 released</title><content type='html'>&lt;a href="http://code.google.com/p/networkpx/downloads/detail?name=hk.kennytm.quickscroll-0.1-12.deb"&gt;QuickScroll 0.1-12 is released.&lt;/a&gt; It's a quick (:p) project done within half a day. &lt;br /&gt;&lt;br /&gt;QuickScroll lets you scroll through a Web page (including PDF files and Word documents) quickly. To use:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;In a long web page, triple tap on anywhere (hold one finger and triple tap the other to avoid resizing).&lt;/li&gt;&lt;li&gt;A dialog will appear. Drag the green box to scroll around.&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src="http://x0e.xanga.com/81cf253038730251702823/w199873521.png" /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-1719385646731716960?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/1719385646731716960/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/08/quickscroll-01-12-released.html#comment-form' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/1719385646731716960'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/1719385646731716960'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/08/quickscroll-01-12-released.html' title='QuickScroll 0.1-12 released'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-8332862453359985847</id><published>2009-08-09T20:51:00.006+08:00</published><updated>2009-08-23T04:22:55.639+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='iKeyEx'/><title type='text'>iKeyEx 0.1-99b is released (3.0 only)</title><content type='html'>Hi girls and guys. 0.1-99f has been released. Maybe check the newest post first before commenting? ;p&lt;br /&gt;&lt;br /&gt;&lt;hr /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://code.google.com/p/networkpx/downloads/detail?name=hk.kennytm.iKeyEx3-0.1-99b.deb"&gt;iKeyEx 0.1-99b is released.&lt;/a&gt; This is a beta version, and the release version will use the version number "0.2". &lt;br /&gt;&lt;br /&gt;&lt;hr /&gt;&lt;br /&gt;&lt;br /&gt;Compared with the iKeyEx 2.x series, a lot of things are changed that may render an existing keyboard useless.&lt;br /&gt;&lt;br /&gt;Firstly, &lt;em&gt;text with traits are not supported yet&lt;/em&gt;, meaning keyboard that entirely relying on it such as &lt;strong&gt;1Click@Thai&lt;/strong&gt; (com.iclick.thai5rowkeyboard) will entirely unusable in this version. &lt;br /&gt;&lt;br /&gt;Secondly, &lt;em&gt;libiKeyEx.dylib&lt;/em&gt; is rewritten and uses a different API. That means existing keyboard more complex than a standard keyboard, including &lt;strong&gt;ℏClipboard&lt;/strong&gt; and &lt;strong&gt;5 Row QWERTY&lt;/strong&gt; cannot run. If dependence is not a lot, however, transition to 3.x is pretty easy.&lt;br /&gt;&lt;br /&gt;Thirdly, the input mode architecture is changed. Previously, an input mode linked to exactly one layout. It is decoupled on 0.1-99b. For example, I can have a 5-row QWERTY keyboard for English, for Japanese and for Chinese simultaneously. You can do it in the Mix &amp; Match options in Settings &amp;rarr; iKeyEx. But because a layout no longer completely defines an input mode, installing a keyboard may not be immediately usable. &lt;br /&gt;&lt;br /&gt;&lt;u&gt;Example 1:&lt;/u&gt; The &lt;strong&gt;Deutsch 5 Row Keyboard&lt;/strong&gt; (com.ipuhelin.keyboards-5rowdeutsch) will be installed using English (US) as input manager. You can fix it by choosing Settings &amp;rarr; iKeyEx &amp;rarr; Mix and Match &amp;rarr; 5RowDeutsch &amp;rarr; Input manager &amp;rarr; German (Germany).&lt;br /&gt;&lt;br /&gt;&lt;u&gt;Example 2:&lt;/u&gt; The &lt;strong&gt;Dvorak 5Row Keyboard&lt;/strong&gt; (hk.alim.dvorak5row) was installed without adding itself to the list of input modes. In 2.x you'd add it from International Keyboards, but this is more complicated on 3.x due to the decoupling. The procedure can be summarized into this pic:&lt;br /&gt;&lt;p&gt;&lt;img src="http://xd2.xanga.com/708f513111c33251666343/w199841304.png" /&gt;&lt;/p&gt;&lt;br /&gt;In words,&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Go to Settings &amp;rarr; iKeyEx&lt;/li&gt;&lt;li&gt;Select "Mix and Match",&lt;/li&gt;&lt;li&gt;then "Create", to create a new input mode.&lt;/li&gt;&lt;li&gt;Now, select "Layout",&lt;/li&gt;&lt;li&gt;and change it to "5-Row DVORAK" at the top.&lt;/li&gt;&lt;li&gt;After that, select "Name"&lt;/li&gt;&lt;li&gt;and give it a name. It must not be empty.&lt;/li&gt;&lt;li&gt;Finally, go back to the iKeyEx screen and tap "Keyboard"&lt;/li&gt;&lt;li&gt;You should be able to see the new input mode. Tap on (+) to add it.&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;I haven't put in any localization yet. They will appear in the next version.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-8332862453359985847?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/8332862453359985847/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/08/ikeyex-01-99b-is-released-30-only.html#comment-form' title='40 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/8332862453359985847'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/8332862453359985847'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/08/ikeyex-01-99b-is-released-30-only.html' title='iKeyEx 0.1-99b is released (3.0 only)'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>40</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-5198709110766529398</id><published>2009-08-07T22:33:00.002+08:00</published><updated>2009-08-07T23:02:01.238+08:00</updated><title type='text'>The 8th property list object</title><content type='html'>We've been long told that there're only 7 types of property list objects: CFString, CFNumber, CFBoolean, CFDate, CFData, CFArray, and CFDictionary. These are the only types that can be encoded into a property list without conversion. At least it's what on the surface. There's in fact an eighth type of property list object, called &lt;strong&gt;_CFKeyedArchiverUID&lt;/strong&gt;, to support the NSKeyed[Un]Archiver.&lt;br /&gt;&lt;br /&gt;An archived data is actually a binary property list. The encoded objects are laid out linearly, and each object has a UID numbered serially. Objects can be linked to each other, forming an "Object Graph". The links are encoded as _CFKeyedArchiverUIDs.&lt;br /&gt;&lt;br /&gt;A _CFKeyedArchiverUID is essentially a 32-bit integer. Why isn't a CFNumber be used? Because it would then be impossible to distinguish between a regular number and a link. &lt;br /&gt;&lt;br /&gt;Becuase _CFKeyedArchiverUID is not publicly documented (you can find its trace in the CF source code), it is a perfect type to conceal these supposed-to-be internal information.&lt;br /&gt;&lt;br /&gt;But it introduce problems when handling with plist files that have a _CFKeyedArchiverUID. Firstly, Apple's &lt;strong&gt;Property List Editor&lt;/strong&gt; does not recognize them. And even worse, these UIDs are stripped when saved. You can try this: open any .nib file, without any modification save it as another file. You'll find that the new file becomes smaller.&lt;br /&gt;&lt;br /&gt;Also, _CFKeyedArchiverUID does not have a specialized -description method. When you NSLog a dictionary containing with object, a &lt;tt&gt;&amp;lt;NSCFType: 0xpointer&amp;gt;&lt;/tt&gt; will be displayed (although CFShow does show the content).&lt;br /&gt;&lt;br /&gt;In XML format, _CFKeyedArchiverUID will be output as&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&amp;lt;dict&amp;gt; &amp;lt;key&amp;gt;CF$UID&amp;lt;/key&amp;gt; &amp;lt;integer&amp;gt;123&amp;lt;/integer&amp;gt; &amp;lt/dict&amp;gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;This means any dictionaries containing a single entry with key CF$UID and an integer value will be converted to a _CFKeyedArchiverUID.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-5198709110766529398?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/5198709110766529398/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/08/8th-property-list-object.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/5198709110766529398'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/5198709110766529398'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/08/8th-property-list-object.html' title='The 8th property list object'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-8958162651609630918</id><published>2009-08-05T12:09:00.003+08:00</published><updated>2009-08-05T12:13:48.219+08:00</updated><title type='text'>LC_DYLD_INFO_ONLY demystified</title><content type='html'>One day after I found no useful info on LC_DYLD_INFO_ONLY, there's already &lt;a href="http://74.125.153.132/search?q=cache:IELRYiJaSrcJ:fr.pastebin.ca/1511696+LC_DYLD_INFO_ONLY&amp;cd=1&amp;hl=en&amp;ct=clnk&amp;client=safari"&gt;a paste&lt;/a&gt; showing the answer (this is Google cache, the original one is already invalidated). I have copied it to &lt;a href="http://pastie.org/572025"&gt;pastie&lt;/a&gt; in case the Google cache is removed. From the comment we clearly see the intent, and hints to how to decode this command.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-8958162651609630918?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/8958162651609630918/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/08/lcdyldinfoonly-demystified.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/8958162651609630918'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/8958162651609630918'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/08/lcdyldinfoonly-demystified.html' title='LC_DYLD_INFO_ONLY demystified'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-6732208108293542576</id><published>2009-08-05T03:11:00.002+08:00</published><updated>2009-08-05T03:59:27.606+08:00</updated><title type='text'>Using CPRegularExpression (not!)</title><content type='html'>AppSupport.framework contains a class called CPRegularExpression, which performs regular expression matching. &lt;a href="http://pastie.org/pastes/571117"&gt;Here is an interface and some sample code&lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;However, I strongly recommend &lt;strong&gt;against&lt;/strong&gt; using this class. Why? Because the &lt;em&gt;backend&lt;/em&gt; of CPRegularExpression is in fact &lt;tt&gt;regexec&lt;/tt&gt;. &lt;tt&gt;regexec&lt;/tt&gt; is underpowered and not fast at all (for commonly encountered regexes, at least). Combined with the dynamic nature of Objective-C it means very slow (you can get an IMP to speed this up though). Instead, you should use the more powerful and faster PCRE (it's of course hard to use, but there're &lt;a href="http://www.cocoadev.com/index.pl?RegularExpressions"&gt;plenty of wrappers&lt;/a&gt;).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-6732208108293542576?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/6732208108293542576/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/08/using-cpregularexpression-not.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/6732208108293542576'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/6732208108293542576'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/08/using-cpregularexpression-not.html' title='Using CPRegularExpression (not!)'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-3300891092302628730</id><published>2009-08-05T02:08:00.003+08:00</published><updated>2009-08-05T03:11:48.845+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='class-dump-z'/><title type='text'>class-dump-z 0.1-11s released.</title><content type='html'>&lt;a href="http://code.google.com/p/networkpx/downloads/detail?name=class-dump-z_0.1-11s.tar.gz"&gt;class-dump-z 0.1-11s&lt;/a&gt; is released. (When iKeyEx 3.0 is released I'll upgrade the versioning to 0.2. Let's hope I won't exhaust all alphabets first.)&lt;br /&gt;&lt;br /&gt;Change log:&lt;ul&gt;&lt;li&gt;Won't crash on 3.1 binaries now, &lt;em&gt;but external class info is absent&lt;/em&gt;. For example, for SpringBoard, &lt;tt&gt;SBAppWindow : UIView&lt;/tt&gt; will be shown as &lt;tt&gt;SBAppWindow : XXUnknownSuperclass&lt;/tt&gt;.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Private ivar detection&lt;/strong&gt;. From whether the ivar symbol is exported we can guess if that ivar is @private/@package or @protected/@public. class-dump-z 0.1-11s now recognizes this piece of information.&lt;/li&gt;&lt;li&gt;&lt;tt&gt;-h super&lt;/tt&gt; now works even the method includes non-id/void/SEL types.&lt;/li&gt;&lt;li&gt;Argument reordering now works on Linux (again).&lt;/li&gt;&lt;/ul&gt;&lt;hr /&gt;&lt;em&gt;Technical detail on why class-dump-z 0.1-11r crash with 3.1 SpringBoard, and why the external class info cannot be extracted in 0.1-11s.&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;If you use class-dump-z 0.1-11r on the 3.1 SpringBoard, you'll get an exception saying &lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;terminate called after throwing an instance of 'std::logic_error'&lt;br /&gt;  what():  basic_string::_S_construct NULL not valid&lt;br /&gt;Abort trap&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;This is because a code similar to this is called:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;std::string s = NULL;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;Debugging reveals such an error occurs at &lt;tt&gt;MachO_File_ObjC::get_superclass_name&lt;/tt&gt;. What happened is that, the definition of SBAppWindow class of 3.1 SpringBoard resolves to:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt; class_t OBJC_CLASS_$_SBAppWindow = {&lt;br /&gt;  isa: OBJC_METACLASS_$_SBAppWindow,&lt;br /&gt;  superclass: NULL,&lt;br /&gt;  cache: NULL,&lt;br /&gt;  vtable: NULL,&lt;br /&gt;  data: (pointer to Data)&lt;br /&gt;};&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;The superclass pointer is NULL. Which is fine, as such already happens before 3.1. But how can the system know the superclass if the pointer is NULL? Before 3.1, this location is in fact referenced by an entry in the &lt;em&gt;relocation table&lt;/em&gt;. At runtime, the dynamic linker will replace data referenced in the relocation table by the real address. &lt;br /&gt;&lt;br /&gt;The problem is the 3.1 SpringBoard has &lt;em&gt;no relocation table&lt;/em&gt;! We can check:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;Load command 6&lt;br /&gt;            cmd LC_DYSYMTAB&lt;br /&gt;        cmdsize 80&lt;br /&gt;      ilocalsym 0&lt;br /&gt;      nlocalsym 1&lt;br /&gt;     iextdefsym 1&lt;br /&gt;     nextdefsym 1&lt;br /&gt;      iundefsym 2&lt;br /&gt;      nundefsym 1330&lt;br /&gt;         tocoff 0&lt;br /&gt;           ntoc 0&lt;br /&gt;      modtaboff 0&lt;br /&gt;        nmodtab 0&lt;br /&gt;   extrefsymoff 0&lt;br /&gt;    nextrefsyms 0&lt;br /&gt; indirectsymoff 1138584&lt;br /&gt;  nindirectsyms 1943&lt;br /&gt;&lt;strong&gt;      extreloff 0&lt;br /&gt;        nextrel 0&lt;br /&gt;      locreloff 0&lt;br /&gt;        nlocrel 0&lt;/strong&gt;&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;Because of this, class-dump-z 0.1-11r cannot resolve what that address will be, and returns NULL. The code afterward see this NULL unexpected and result in exception.&lt;br /&gt;&lt;br /&gt;0.1-11s now checks for this failure, but it's just a bad workaround. Because every externally referred class, like NSObject, UIView, etc. will become XXUnknownSuperclass. &lt;br /&gt;&lt;br /&gt;Now, if we don't know the superclass, how can the iPhoneOS be? There, I introduce you the Load Command 0x80000022:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;Load command 4&lt;br /&gt;      cmd ?(0x80000022) Unknown load command&lt;br /&gt;  cmdsize 48&lt;br /&gt;00000000 00000000 00106000 00006c6c 00000000 00000000 0010cc6c 00005324 &lt;br /&gt;00111f90 00000198&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;It is run without the 3.1 SDK. Because this is an unknown command, nm totally fails on the 3.1 SpringBoard.&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;nm: for architecture armv6 object: SpringBoard malformed object (unknown load command 4)&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;a href="http://www.google.com/search?hl=en&amp;client=safari&amp;rls=en-us&amp;q=%22load+command%22+0x80000022&amp;aq=f&amp;oq=&amp;aqi="&gt;Googling&lt;/a&gt; suggests it appears only on 3.1+ &lt;em&gt;and&lt;/em&gt; Snow Leopard+. That means the ABI will be changed on SL? And relocation table won't be used? Maybe. With a 3.1 SDK, we can see that the load command is in fact called LC_DYLD_INFO_ONLY. The content is&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;&lt;br /&gt;struct dyld_info_only_32 {&lt;br /&gt;  uint32_t rebase_off;&lt;br /&gt;  uint32_t rebase_size;&lt;br /&gt;  uint32_t bind_off; // 0x106000&lt;br /&gt;  uint32_t bind_size; // 0x6c6c&lt;br /&gt;  uint32_t weak_bind_off;&lt;br /&gt;  uint32_t weak_bind_size;&lt;br /&gt;  uint32_t lazy_bind_off; // 0x10cc6c&lt;br /&gt;  uint32_t lazy_bind_size; // 0x5324&lt;br /&gt;  uint32_t export_off; // 0x111f90&lt;br /&gt;  uint32_t export_size; // 0x198&lt;br /&gt;}&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;This load command is &lt;a href="http://developer.apple.com/documentation/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html"&gt;not documented on Apple's site&lt;/a&gt; either, and google yields no useful result at all. But we can find the &lt;strong&gt;string&lt;/strong&gt; &lt;tt&gt;_OBJC_CLASS_$_UIWindow&lt;/tt&gt; at 0x106ea0 inside the so called "bind" table, so definitely something important can be found here.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-3300891092302628730?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/3300891092302628730/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/08/class-dump-z-01-11s-released.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/3300891092302628730'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/3300891092302628730'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/08/class-dump-z-01-11s-released.html' title='class-dump-z 0.1-11s released.'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-8822687334201285603</id><published>2009-08-03T02:46:00.006+08:00</published><updated>2009-08-03T03:07:03.411+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='iKeyEx'/><title type='text'>Partial support for iKeyEx layout.plist on 3.0</title><content type='html'>The layout.plist to UIKBKeyboard conversion function is done. &lt;a href="http://networkpx.blogspot.com/2009/07/text-input-on-30-part-4.html"&gt;As promised&lt;/a&gt;, an executable that converts layout.plist to .keyboard files can be downloaded from &lt;a href="http://code.google.com/p/networkpx/downloads/detail?name=layout-plist-to-keyboards"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;This program converts a layout.plist into 8 .keyboard files which can be loaded by UIKit natively. For example, if you want to install the Colemak keyboard,&lt;br /&gt;&lt;ol&gt;&lt;li&gt;ssh into your device&lt;/li&gt;&lt;li&gt;Download layout-plist-to-keyboards by typing:&lt;blockquote&gt;&lt;pre&gt;wget http://networkpx.googlecode.com/files/layout-plist-to-keyboards&lt;/pre&gt;&lt;/blockquote&gt;&lt;/li&gt;&lt;li&gt;Change that file to an executable:&lt;blockquote&gt;&lt;pre&gt;chmod a+x layout-plist-to-keyboards&lt;/pre&gt;&lt;/blockquote&gt;&lt;/li&gt;&lt;li&gt;Download the layout.plist for Colemak:&lt;blockquote&gt;&lt;pre&gt;wget http://networkpx.googlecode.com/svn/trunk/hk.kennytm.Colemak/deb/Library/iKeyEx/Keyboards/Colemak.keyboard/layout.plist&lt;/pre&gt;&lt;/blockquote&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Perform the conversion:&lt;/strong&gt;&lt;blockquote&gt;&lt;pre&gt;./layout-plist-to-keyboards layout.plist&lt;/blockquote&gt;&lt;/li&gt;&lt;li&gt;Check that there are 8 .keyboard files in the directory.&lt;/pre&gt;&lt;blockquote&gt;&lt;pre&gt;ls&lt;/pre&gt;&lt;/blockquote&gt;&lt;/li&gt;&lt;li&gt;Move all these keyboards to UIKit.framework (requires root permission):&lt;blockquote&gt;&lt;pre&gt;mv *.keyboard /System/Library/Frameworks/UIKit.framework/&lt;/pre&gt;&lt;/blockquote&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;Now all QWERTY keyboards are replaced by Colemak. &lt;br /&gt;&lt;br /&gt;If you don't want to replace the QWERTY keyboard, you can rename them to something else. Say, you'll never use the Thai keyboard, then name them &lt;tt&gt;iPhone-Portrait-Thai.keyboard&lt;/tt&gt;, etc. Now you can activate the Thai keyboard to use the custom one.&lt;br /&gt;&lt;br /&gt;This solution is not a replacement of a full iKeyEx. For example, 5-Row QWERTY won't work completely because the custom-code injecting part is not done yet (but Punctuation Mod should work). hClipboard won't work at all since it's no a layout.plist.  Other caveats are &lt;a href="http://code.google.com/p/networkpx/wiki/Creating_layout_plist?ts=1249239078&amp;updated=Creating_layout_plist"&gt;listed here&lt;/a&gt;. &lt;strong&gt;Please don't host Cydia packages publicly that uses this solution,&lt;/strong&gt; because every keyboard will become mutually exclusive now :) Only for personal use.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-8822687334201285603?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/8822687334201285603/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/08/partial-30-support-for-ikeyex.html#comment-form' title='49 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/8822687334201285603'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/8822687334201285603'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/08/partial-30-support-for-ikeyex.html' title='Partial support for iKeyEx layout.plist on 3.0'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>49</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-3678772270305430194</id><published>2009-08-01T22:29:00.003+08:00</published><updated>2009-08-02T16:40:55.528+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='class-dump-z'/><title type='text'>class-dump-z 0.1-11r released, supports Windows</title><content type='html'>A minor revision of class-dump-z was released. The new version:&lt;ul&gt;&lt;li&gt;Adds a Windows x86 version.&lt;/li&gt;&lt;li&gt;Arguments can be placed arbitrarily (e.g. &lt;tt&gt;class-dump-z UIKit -a -A&lt;/tt&gt; now works).&lt;/li&gt;&lt;/ul&gt;Updated on Aug 2:&lt;ul&gt;&lt;li&gt;If you have installed the iPhone SDK, the -y switch is no longer necessary when using -h super.&lt;/li&gt;&lt;li&gt;Also, using -h super won't crash now.&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-3678772270305430194?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/3678772270305430194/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/08/class-dump-z-01-11r-released-supports.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/3678772270305430194'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/3678772270305430194'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/08/class-dump-z-01-11r-released-supports.html' title='class-dump-z 0.1-11r released, supports Windows'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-5342560267035749580</id><published>2009-08-01T11:33:00.004+08:00</published><updated>2009-08-01T11:36:51.984+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GriP'/><title type='text'>GriP 0.1-11r Released to fix Crashing with Exchange mail accounts</title><content type='html'>As titled. If you are experience crashes when new mails arrive to an Exchange mail account, please upgrade to GriP 0.1-11r. Detail can be found in &lt;a href="http://code.google.com/p/networkpx/issues/detail?id=242"&gt;issue 242&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-5342560267035749580?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/5342560267035749580/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/08/grip-01-11r-released-to-fix-crashing.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/5342560267035749580'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/5342560267035749580'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/08/grip-01-11r-released-to-fix-crashing.html' title='GriP 0.1-11r Released to fix Crashing with Exchange mail accounts'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-3387512995378167619</id><published>2009-07-31T22:00:00.003+08:00</published><updated>2009-07-31T22:36:29.886+08:00</updated><title type='text'>GriP, GriPGRIP &amp; class-dump-z 0.1-11q Released</title><content type='html'>Starting from this version, Memory Watcher will not be included in GriP. Instead, it will be moved to a new package, "GriP Really Impressive Pack" (GriPGRIP). The distinction is that, GriP shall only contains the most needed extensions, i.e.&lt;ul&gt;&lt;li&gt;Mail&lt;/li&gt;&lt;li&gt;Push notification&lt;/li&gt;&lt;li&gt;SMS (&lt;a href="http://code.google.com/p/iphone-quickreply/downloads/list"&gt;by xshad0w&lt;/a&gt;, not included in 0.1-11q yet),&lt;/li&gt;&lt;/ul&gt;the 2 themes, Default and Double Height Status Bar (also by xshad0w, also not included yet), and 3 modal table themes, Default, HUD and Translucent Black (I may remove the last one too). On the other hand, GriPGRIP is a collection of all other stuff that will utilize GriP, like calendar events, remote Growl notifications, themes, etc. (The distinction is because GriP is growing to 1 MiB pretty soon. I want to keep the size down.)&lt;br /&gt;&lt;br /&gt;&lt;hr /&gt;&lt;br /&gt;&lt;br /&gt;Anyway, 0.1-11q is mainly an issue-fixing release, that include:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://code.google.com/p/networkpx/issues/detail?id=223"&gt;Issue 223&lt;/a&gt;. You can configure some GriP messages to wake the device up.&lt;/li&gt;&lt;li&gt;&lt;a href="http://code.google.com/p/networkpx/issues/detail?id=176"&gt;Issue 176&lt;/a&gt;. An new option so that GriP message can be expanded by default.&lt;/li&gt;&lt;li&gt;&lt;a href="http://code.google.com/p/networkpx/issues/detail?id=209"&gt;Issue 209&lt;/a&gt;. You've Got Mail will show the user name of the mail owner, instead of the address.&lt;/li&gt;&lt;li&gt;&lt;a href="http://code.google.com/p/networkpx/issues/detail?id=168"&gt;Issue 168&lt;/a&gt;. All apps can be selected shown in Game Mode. The UI is improved too :)&lt;/li&gt;&lt;li&gt;&lt;a href="http://code.google.com/p/networkpx/issues/detail?id=172"&gt;Issue 172&lt;/a&gt;. Multiple push notifications from the same app will be coalesced.&lt;/li&gt;&lt;li&gt;Suspension behavior can be updated properly.&lt;/li&gt;&lt;/ul&gt; &lt;br /&gt;&lt;br /&gt;If you have GriP 0.1-11p, you don't need GriPGRIP 0.1-11q, because there's nothing new.&lt;br /&gt;&lt;br /&gt;&lt;hr /&gt;&lt;br /&gt;&lt;br /&gt;And class-dump-z. There are 4 new features in this release:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The &lt;strong&gt;-N&lt;/strong&gt; flag, which allows you to disable struct name prettifying (__CFArray* &amp;rarr; CFArrayRef).&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Optional properties&lt;/strong&gt;. Such a thing does not exist directly, but can be inferred when its getter and setter are optional. (See the UITextTraits protocol for example).&lt;/li&gt;&lt;li&gt;The &lt;strong&gt;-h proto&lt;/strong&gt; flag, which will hide all methods that's just adopting a protocol.&lt;/li&gt;The &lt;strong&gt;-h super&lt;/strong&gt; flag, which will hide all inherited methods.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Note that if you use the &lt;strong&gt;-h super&lt;/strong&gt; flag directly on the Mac, it is almost certain that class-dump-z will crash. This is because to get the superclass info class-dump-z must open some framework bundles, and by default it will search in /System/Library/..., which certainly does not contain anything iPhoneOS-related. You have to provide the -y flag to specify the sysroot as well. For those who have installed SDK, you need to add&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;-y /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.0.sdk&lt;/pre&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-3387512995378167619?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/3387512995378167619/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/07/grip-gripgrip-class-dump-z-01-11q.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/3387512995378167619'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/3387512995378167619'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/07/grip-gripgrip-class-dump-z-01-11q.html' title='GriP, GriPGRIP &amp; class-dump-z 0.1-11q Released'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-1634242094693654978</id><published>2009-07-30T14:14:00.002+08:00</published><updated>2009-07-30T18:46:54.849+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='iKeyEx'/><title type='text'>Text input on 3.0, Part 4 — UIKBKeylistReference</title><content type='html'>&lt;ul&gt;&lt;li&gt;When I was preparing this whole stuff many wrong directions were taken and generates quite a number of utilities that could be useful later. Who knows? Head to &lt;a href="http://code.google.com/p/networkpx/source/browse/etc"&gt;http://code.google.com/p/networkpx/source/browse/etc&lt;/a&gt; if you are interested. &lt;/li&gt;&lt;li&gt;You will need UIKB*.h to compile my examples. The headers can be found in my other project page at &lt;a href="http://github.com/kennytm/iphone-private-frameworks/tree/master"&gt;github&lt;/a&gt;. However, besides ActorKit no header there is actually complete (yet).&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;hr /&gt;&lt;br /&gt;&lt;br /&gt;Hopefully it's the last of the series. I'm now making a convert from layout.plist to .keyboard files. This is a major foundation for backward-compatibility with previous keyboards, and also allows you to use custom keyboards on 3.0 &lt;em&gt;without&lt;/em&gt; iKeyEx (but, without all the benefits like unlimited numbers of keyboards). The basic idea is described in &lt;a href="http://networkpx.blogspot.com/2009/07/text-input-on-30-part-1.html"&gt;Part 1&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;del&gt;Anyway...&lt;/del&gt;&lt;br /&gt;&lt;br /&gt;Unlike the old UIKeyboardLayoutRoman, the new UIKeyboardLayoutStar is "scalable", that means this keyboard will still look sharp even if used on a 10" tablet PC. This is because the whole UIKeyboardLayoutStar is drawn at run time with Rounded rectangles and Gradients and Shadows and stuff. It's vector graphics. (In constrast, UIKeyboardLayoutRoman is precomposed into a PNG image.)&lt;br /&gt;&lt;br /&gt;But even the layout has the potential to be scalable, all keyboards I've created before (using Star) is &lt;em&gt;not&lt;/em&gt;, because I haven't told it &lt;em&gt;what&lt;/em&gt; to scale. It's like an iPhone app, most of them can be easily presented in landscape mode, but if the programmer doesn't implement the -shouldAutorotateToInterfaceOrientation: method the app will always stuck in portrait mode.&lt;br /&gt;&lt;br /&gt;As I've repeated many times, keyboard construction occupies 70% mass of UIKit, and that's roughly 8 MiB of code. There are 148 keyboards defined in UIKit so far, so each keyboard will be defined by 55 KiB of code and data. And unfortunately, most of these are code. Now, ARM's register-relative addressing mode allows a maximum span of 11 bits, i.e. 8 KiB, but there's 55 KiB of code! That means each single function must be chopped into chunks by the compiler. To the analyzing decompiler (ravel-arm), it is a difficult situation, because an unconditional branch at the end may mean a tail-function-call. The data after may be interpreted as code, and ruins all stored computation in between. This is happening in the keyboard-defining functions, so by static analyzing the code I can only get to how Apple defines keys up to the Capital Letter U (that's Q, W, E, R, T, Y, U), and then a branch across some mis-codified data, and all selector and class info are lost.&lt;br /&gt;&lt;br /&gt;So? Initially I &lt;a href="http://code.google.com/p/networkpx/source/browse/etc/dump-keyboard.m"&gt;dumped all 148 keyboards&lt;/a&gt; and analyzed the &lt;a href="http://code.google.com/p/networkpx/source/browse/etc/visualize-archived-object.c"&gt;resulting archive&lt;/a&gt;, but this doesn't tell us the implementation detail. Eventually I &lt;a href="http://code.google.com/p/networkpx/source/browse/etc/objc_msgSend_hook.mm"&gt;hooked objc_msgSend&lt;/a&gt; to give what's being called (since I knew only Obj-C functions are called and no structs are returned, I've ignored all other messaging variants).&lt;br /&gt;&lt;br /&gt;The result is over 9000 bytes and I can't pastie it. But I can pastie &lt;a href="http://pastie.org/565027"&gt;part of the decompiled result&lt;/a&gt;. The UIKBKeylistReference part is what I was missing. Now let's plug in the keyboard, and we get... a dangling Q as we've expected.&lt;br /&gt;&lt;img src="http://x87.xanga.com/8c8f4b4022635250683383/w198980908.png" /&gt;&lt;br /&gt;But if we resize the keyboard from 320x216 to 240x216? Yes, the key is correctly scaled down:&lt;br /&gt;&lt;img src="http://xc1.xanga.com/84ff564740c33250683850/w198981321.png" /&gt;&lt;br /&gt;And removing the references even make the dimensions wrong, so the scaling is really the reference in effect.&lt;br /&gt;&lt;img src="http://xc8.xanga.com/44ff4a40c8235250684126/w198981587.png" /&gt;&lt;br /&gt;(When the reference is defined, the original geometry of the keys will be overridden).&lt;br /&gt;(Also note that this keyboard cannot be scaled &lt;em&gt;vertically&lt;/em&gt;, because the vertical measures of the rows are &lt;em&gt;absolute&lt;/em&gt; values (pixels).)&lt;br /&gt;&lt;br /&gt;One puzzling property of references is the "flag". Yes we know it must be bitfield of some sort, but what? If we decompile the class UIKBKeylistReference we get:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;1 = isKeysetReference&lt;/li&gt;&lt;li&gt;2 = isKeylistReference&lt;/li&gt;&lt;li&gt;4 = isKeysReference&lt;/li&gt;&lt;li&gt;8 = isNamedKeyReference &lt;/li&gt;&lt;li&gt;0x10 = isKeyIndexReference &lt;/li&gt;&lt;li&gt;0x20 = isKeyIndexRangeReference &lt;/li&gt;&lt;li&gt;0x40 = isGeometryReference&lt;/li&gt;&lt;li&gt;0x80 = isAttributesReference &lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Apparently it refers to while the name elements interpreted.&lt;br /&gt;&lt;br /&gt;Why we care about scaling? One, it allows us to define landscape and portrait keyboards with the same content (the keys), and to switch between the two we just need to change the outermost dimension, and the rest will be seamlessly changed. And two, who said the keyboard size must be fixed at 320x216 / 480x162? What if there is really an Apple tablet and uses the iPhoneOS? Or there's an iPhone mini? The resolution can't be the same, so the keyboard size must be altered as well. On 2.x we're forced to hard-code these 4 numbers because UIKeyboardLayoutRoman expects us to do so. Now having the better solution with UIKeyboardLayoutStar, I'd rather spend more time to take advantage of it and make iKeyEx more robust in the future.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-1634242094693654978?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/1634242094693654978/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/07/text-input-on-30-part-4.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/1634242094693654978'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/1634242094693654978'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/07/text-input-on-30-part-4.html' title='Text input on 3.0, Part 4 — UIKBKeylistReference'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-1733061070582724780</id><published>2009-07-27T17:20:00.004+08:00</published><updated>2009-07-27T17:52:23.378+08:00</updated><title type='text'>Multiple Row Selection with UITableView — The Easy Way</title><content type='html'>&lt;a href="http://cocoawithlove.com/2009/01/multiple-row-selection-and-editing-in.html"&gt;Cocoa with Love&lt;/a&gt; introduced the hard way to implement multiple row selection for 2.x firmware. On 3.x, there is a much easier way to do the same, if you dare you embrace undocumented methods.&lt;br /&gt;&lt;br /&gt;Multi-selection is regarded as one of the editing style. Therefore, to make a cell multi-selectable, implement this in your UITableViewDelegate:&lt;br /&gt;&lt;pre&gt;-(UITableViewCellEditingStyle)tableView:(UITableView*)tableView editingStyleForRowAtIndexPath:(NSIndexPath*)indexPath {&lt;br /&gt;  ...&lt;br /&gt;  return 3;&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;The "3" here means multiselection. The result is like this:&lt;br /&gt;&lt;img src="http://xa7.xanga.com/48df5aea09532250387261/w198718819.png" /&gt;&lt;br /&gt;&lt;br /&gt;To get the selected rows, call the -indexPathsForSelectedRows method on the table view.&lt;br /&gt;&lt;pre&gt;NSArray* selectedRows = [tableView indexPathsForSelectedRows];&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;If you dislike the red check mark, you can use the undocumented multiselectCheckmarkColor property to change it. Unfortunately, it has to be applied on the whole table.&lt;br /&gt;&lt;pre&gt;tableView.multiselectCheckmarkColor = [UIColor blueColor];&lt;/pre&gt;&lt;br /&gt;The light blue background color cannot be changed unless you subclass or categorize UITableViewCell and override the -_multiselectBackgroundColor method, like this:&lt;br /&gt;&lt;pre&gt;-(UIColor*)_multiselectBackgroundColor { return [UIColor yellowColor]; }&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-1733061070582724780?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/1733061070582724780/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/07/multiple-row-selection-with-uitableview.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/1733061070582724780'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/1733061070582724780'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/07/multiple-row-selection-with-uitableview.html' title='Multiple Row Selection with UITableView — The Easy Way'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-3102164792293791006</id><published>2009-07-18T06:14:00.003+08:00</published><updated>2009-07-18T08:00:29.482+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='class-dump-z'/><category scheme='http://www.blogger.com/atom/ns#' term='GriP'/><title type='text'>class-dump-z &amp; GriP 0.1-11p released</title><content type='html'>Downloads available in &lt;a href="http://code.google.com/p/networkpx/downloads/list"&gt;http://code.google.com/p/networkpx/downloads/list&lt;/a&gt; as usual.&lt;br /&gt;&lt;br /&gt;What's new in GriP: Again, another attempt to fix issue 129.&lt;br /&gt;&lt;br /&gt;What's new in class-dump-z:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Doesn't crash with WebKit.framework anymore.&lt;ul&gt;&lt;li&gt;The offending struct is XXStruct_GIci6C. Due to some strange thing  in the GCC that compiles WebKit, the type of function pointer is encoded into "^" (pointer to !#$^*@#NO_CARRIER) instead of "^?" (pointer to some unknown stuff). The original class-dump won't handle this stuff either, and spit out a huge error string.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;Doesn't crash with Symbolication.framework anymore.&lt;ul&gt;&lt;li&gt;The offending class is VMUCallTreeNode, which contains a union to a pointer to a static-typed objective-C class, which will cause a segfault in 0.1-11o. This was just an error in class-dump-z.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;Forward declaration of some structs were missing if it is nested. Not anymore.&lt;/li&gt;&lt;li&gt;Fixed issue 187. It was because class-dump-z missed the LC_LOAD_WEAK_DYLIB commands.&lt;/li&gt;&lt;li&gt;Fixed issue 198.&lt;/li&gt;&lt;li&gt;Linux version: PCRE is static-linked. No need to search for the right version of libpcre.so anymore.&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-3102164792293791006?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/3102164792293791006/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/07/class-dump-z-grip-01-11p-released.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/3102164792293791006'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/3102164792293791006'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/07/class-dump-z-grip-01-11p-released.html' title='class-dump-z &amp; GriP 0.1-11p released'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-2583292415916425192</id><published>2009-07-09T02:53:00.002+08:00</published><updated>2009-07-09T03:11:18.364+08:00</updated><title type='text'>Analyzing Objective-C's for-in loop (fast enumeration)</title><content type='html'>Objective-C 2.0 supports for-in loop like this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;for (XXSomeClass* obj in someArray) {&lt;br /&gt;  [obj doSomething];&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;it's nice to the programmer, but painful for the disassemblers because the simple loop above is translated into this bulky ASM:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;            ldr               r1,[pc,#0xe8]&lt;br /&gt;            mov               r3,#0x0&lt;br /&gt;            str               r3,[sp,#0x44] // state&lt;br /&gt;            str               r3,[sp,#0x48] // itemsPtr&lt;br /&gt;            str               r3,[sp,#0x4c] // mutationsPtr&lt;br /&gt;            str               r3,[sp,#0x50] // extra[0]&lt;br /&gt;            str               r3,[sp,#0x54] // extra[1]&lt;br /&gt;            str               r3,[sp,#0x58] // extra[2]&lt;br /&gt;            str               r3,[sp,#0x5c] // extra[3]&lt;br /&gt;            str               r3,[sp,#0x60] // extra[4]&lt;br /&gt;            ldr               sl,[pc,r1]&lt;br /&gt;            add               r3,r3,#0x10&lt;br /&gt;            str               r3,[sp]&lt;br /&gt;            mov               r1,sl&lt;br /&gt;            add               r2,sp,#0x44&lt;br /&gt;            add               r3,sp,#0x4&lt;br /&gt;            bl                objc_msgSend (stub)               ; [someArray countByEnumeratingWithState: objects:count:]&lt;br /&gt;            subs              r5,r0,#0x0&lt;br /&gt;            beq               loc_000100&lt;br /&gt;            ldr               r3,[sp,#0x4c]&lt;br /&gt;            ldr               r3,[r3]&lt;br /&gt;            mov               r6,r3&lt;br /&gt;loc_000094: mov               r4,#0x0&lt;br /&gt;            b                 loc_0000a4&lt;br /&gt;loc_00009c: ldr               r3,[sp,#0x4c]&lt;br /&gt;            ldr               r3,[r3]&lt;br /&gt;loc_0000a4: cmp               r6,r3&lt;br /&gt;            beq               loc_0000b4&lt;br /&gt;            mov               r0,r8&lt;br /&gt;            bl                objc_enumerationMutation (stub)&lt;br /&gt;loc_0000b4: nop               &lt;br /&gt;            nop               &lt;br /&gt;            nop               &lt;br /&gt;            nop               &lt;br /&gt;            nop               &lt;br /&gt;            add               r4,r4,#0x1&lt;br /&gt;            cmp               r5,r4&lt;br /&gt;            bhi               loc_00009c&lt;br /&gt;            mov               r3,#0x10&lt;br /&gt;            str               r3,[sp]&lt;br /&gt;            mov               r0,r8&lt;br /&gt;            mov               r1,sl                             ; "countByEnumeratingWithState:objects:count:"&lt;br /&gt;            add               r2,sp,#0x44&lt;br /&gt;            add               r3,sp,#0x4&lt;br /&gt;            bl                objc_msgSend (stub)               ; [? ?]&lt;br /&gt;            subs              r5,r0,#0x0&lt;br /&gt;            ldrne             r3,[sp,#0x4c]&lt;br /&gt;            ldrne             r3,[r3]&lt;br /&gt;            bne               loc_000094&lt;br /&gt;loc_000100: ... &lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The disassembled code is&lt;br /&gt;&lt;pre&gt;NSFastEnumerationState enumState;&lt;br /&gt;enumState.state = 0;&lt;br /&gt;enumState.itemsPtr = NULL;&lt;br /&gt;enumState.mutationsPtr = 0;&lt;br /&gt;enumState.extra[0] = 0;&lt;br /&gt;enumState.extra[1] = 0;&lt;br /&gt;enumState.extra[2] = 0;&lt;br /&gt;enumState.extra[3] = 0;&lt;br /&gt;enumState.extra[4] = 0;&lt;br /&gt;NSUInteger count = 16;&lt;br /&gt;id buffer[10];&lt;br /&gt;do {&lt;br /&gt; NSUInteger copiedItemsCount = [someArray countByEnumeratingWithState:&amp;enumState objects:buffer count:count];&lt;br /&gt; for (unsigned long i = 0; i &lt; copiedItemsCount; ++ i) {&lt;br /&gt;  if (*(enumState.mutationsPtr) != 0)&lt;br /&gt;   objc_enumerationMutation(someArray);&lt;br /&gt;  [enumState.itemsPtr[i] doSomething];&lt;br /&gt; }&lt;br /&gt;} while(copiedItemsCount != 0);&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;What does the state and extra do? Up to the implementor. (And objc_enumerationMutation simply kills the program and reports that a mutation happened.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-2583292415916425192?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/2583292415916425192/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/07/analyzing-objective-cs-for-in-loop-fast.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/2583292415916425192'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/2583292415916425192'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/07/analyzing-objective-cs-for-in-loop-fast.html' title='Analyzing Objective-C&apos;s for-in loop (fast enumeration)'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-4751487092863432550</id><published>2009-07-08T02:40:00.003+08:00</published><updated>2009-07-08T23:37:42.701+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='iKeyEx'/><title type='text'>Text input on 3.0, Part 3 -- Hooking</title><content type='html'>I think the best solution for now is put a hook at -[UIKeyboardLayoutStar setKeyboardName:appearance:]. If we see a custom name, we could put our own keyboard into the cache dictionary.&lt;br /&gt;&lt;br /&gt;Who called -[UIKeyboardLayoutStar setKeyboardName:appearance:]? From the backtrace,&lt;br /&gt;&lt;pre&gt;#1  0x30b16dae in -[UIKeyboardLayoutStar showKeyboardType:appearance:orientation:] ()&lt;br /&gt;#2  0x30a1da78 in -[UIKeyboardImpl updateLayout] ()&lt;br /&gt;#3  0x30a1a175 in -[UIKeyboardImpl setDelegate:force:] ()&lt;br /&gt;#4  0x30a1815a in -[UIKeyboardImpl setDelegate:] ()&lt;/pre&gt;&lt;br /&gt;and the calling code of -[UIKeyboardLayoutStar showKeyboardType:appearance:orientation:] is&lt;br /&gt;&lt;pre&gt;[self setKeyboardName:UIKeyboardGetKBStarKeyboardName(&lt;br /&gt;                       UIKeyboardGetCurrentInputMode(),&lt;br /&gt;                       orientation, keyboardType)&lt;br /&gt;           appearance:appearance];&lt;/pre&gt;&lt;br /&gt;and UIKeyboardGetKBStarKeyboardName is hard-coded to generate the expected keyboard name. But before we start we must ensure the input mode can be handled by UIKit! In 3.0 there's a function UIKeyboardGetSupportedInputModes() which returns the 46 hard-coded input mode names. Well, we could of course use MSHookFunction to replace it, but I'd like to see if it's possible to do it with Objective-C only, because MSHookFunction is not available on x86. And actually there is a trick — we see that UIKeyboardGetSupportedInputModes() returns a shared object, which is an NSMutableArray*. What does this mean? Well, we can call this function once on initialization, modify it, and from that point on UIKeyboardGetSupportedInputModes() will record our change. &lt;br /&gt;&lt;br /&gt;Then we need to trick UIKit into thinking our keyboard uses UIKeyboardLayoutStar. This information is extracted in UIKeyboardInputModeUsesKBStar(), which is again hard-coded. However, this function uses an NSDictionary* which cannot be accessed outside. So we can't test on simulator? Not really, we could actually hook -[NSDictionary initWithObjectsAndKeys:] instead, and swap it back to the original method when done. &lt;br /&gt;&lt;br /&gt;There are a few other hard-coded dictionary in UIKeyboardInputManagerClassForInputMode(), UIKeyboardLayoutDefaultTypeForInputModeIsASCIICapable(), UIKeyboardGetKBStarKeyboardName(), etc. After all these are replaced we can get a totally empty keyboard without error — a good start.&lt;br /&gt;&lt;br /&gt;Now we can insert the actual hook to -setKeyboardName:appearance: and set the keyboard. This part is not difficult because there's are reference implementations, like that disassembly of getKeyboardiPhonePortraitQWERTY() and dump of various keyboard files.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-4751487092863432550?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/4751487092863432550/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/07/text-input-on-30-part-3-hooking.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/4751487092863432550'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/4751487092863432550'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/07/text-input-on-30-part-3-hooking.html' title='Text input on 3.0, Part 3 -- Hooking'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-5932537108133042503</id><published>2009-07-06T20:15:00.002+08:00</published><updated>2009-07-07T08:25:43.720+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='iKeyEx'/><title type='text'>Text input on 3.0, Part 2.</title><content type='html'>In the last part, we found that we may be able to use the .keyboard format via GetKeyboardDataFromBundle(). This function is only called from -[UIKeyboardLayoutStar setKeyboardName:appearance:], and is not exported, so it seems .keyboard really only contains the keyboard geometry.&lt;br /&gt;&lt;br /&gt;To see if it really works, let's save an internal keyboard into a file:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;[NSKeyedArchiver archiveRootObject:UIKBGetKeyboardByName(@"iPhone-Portrait-Arabic") toFile:@"/tmp/iPhone-Portrait-Arabic.keyboard"]&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;unfortunately, UIKBGetKeyboardByName is not an exported symbol, so we have to use nlist or &lt;a href="http://pastie.org/485348"&gt;lookup_function_pointers&lt;/a&gt;. Now, rename this file to e.g. iPhone-Portrait-QWERTY.keyboard (the English keybaord) and place it to UIKit.framework — and, indeed, the English keyboard becomes Arabic!&lt;br /&gt;&lt;br /&gt;But how to create a UIKBKeyboard? A UIKBKeyboard has 3 major components: name (NSString*), visualStyle (NSString*) and keyplanes (NSArray*). The name is just the name you'd expect (iPhone-Portrait-Arabic), while the visualStyle must be one of @"iPhone-Standard" or @"iPhone-Alert". These are easy to construct. The meat are all in the keyplanes variable. The keyplanes is an array of &lt;a href="http://pastie.org/535576"&gt;UIKBKeyplane*&lt;/a&gt;. Difference keyplanes are switched between using the shift and 123/ABC keys. Again, each keyplane has a name (NSString*, e.g. @"Capital-Letters"); keylayouts, an array of UIKBKeylayout*; attributes, a UIKBAttributeList* and finally supported-types, an array of NSString*, etc., etc...&lt;br /&gt;&lt;br /&gt;The content is summarized into &lt;a href="http://code.google.com/p/networkpx/wiki/keyboard_file_spec"&gt;http://code.google.com/p/networkpx/wiki/keyboard_file_spec&lt;/a&gt;. With the format analyzed, we can try to create our own keyboard using this new format.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-5932537108133042503?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/5932537108133042503/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/07/text-input-on-30-part-2.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/5932537108133042503'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/5932537108133042503'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/07/text-input-on-30-part-2.html' title='Text input on 3.0, Part 2.'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-1090528049702072301</id><published>2009-07-06T03:56:00.002+08:00</published><updated>2009-07-06T05:36:08.204+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='iKeyEx'/><title type='text'>Text input on 3.0, Part 1.</title><content type='html'>2 little notes:&lt;ol&gt;&lt;li&gt;&lt;a href="http://code.google.com/p/networkpx/downloads/detail?name=hk.kennytm.grip-0.1-11o.deb"&gt;GriP 0.1-11o&lt;/a&gt; has been released to fix &lt;a href="http://code.google.com/p/networkpx/issues/detail?id=129"&gt;issue 129&lt;/a&gt;, and that's the only change.&lt;/li&gt;&lt;li&gt;&lt;a href="http://code.google.com/p/networkpx/downloads/detail?name=class-dump-z.tar.gz"&gt;class-dump-z 0.1-11o&lt;/a&gt; has been released for Mac, iPhone and Linux. See &lt;a href="http://code.google.com/p/networkpx/wiki/class_dump_z"&gt;this page&lt;/a&gt; for a comparison of other class-dumps.&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;hr /&gt;&lt;br /&gt;&lt;blockquote&gt;The rest of this text is written at the same time I'm doing the reverse engineering. You may feel confused, because that's how researching goes.&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;The text input framework is greatly revamped in 3.0. The new UIKit, which is 5 times bigger than 2.0, has 70% of weight taken up by keyboard layouts. And the nontrivial letter-based input managers, once part of UIKit, is moved into its private framework, TextInput.&lt;br /&gt;&lt;br /&gt;What was changed? As the first try, let's view the &lt;a href="http://networkpx.blogspot.com/2009/06/displaying-uiview-hierarchy-in-runtime.html"&gt;view hierarchy&lt;/a&gt;, although this time we can do it in compile time. From the class-dump we know the old UIKeyboard class is still there, so let's run the statement&lt;br /&gt;&lt;code&gt;UILogViewHierarchy( [UIKeyboard activeKeyboard] );&lt;/code&gt;&lt;br /&gt;when the keyboard is present.&lt;br /&gt;&lt;br /&gt;So we got this with the English keyboard:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;UIKeyboard: 0xd47980; frame = (0 264; 320 216); opaque = NO; layer = &amp;lt;CALayer: 0xd47d00&amp;gt;&amp;gt; ({{0, 264}, {320, 216}}, (null), #0, 3)&lt;br /&gt;..&amp;lt;UIKeyboardImpl: 0xd3da20; frame = (0 0; 320 216); opaque = NO; layer = &amp;lt;CALayer: 0xd37b40&amp;gt;&amp;gt; ({{0, 0}, {320, 216}}, (null), #0, 3)&lt;br /&gt;....&amp;lt;UIKeyboardLayoutStar: 0xd48650; frame = (0 0; 320 216); layer = &amp;lt;CALayer: 0xd4ba40&amp;gt;&amp;gt; ({{0, 0}, {320, 216}}, (null), #0, 3)&lt;br /&gt;......&amp;lt;UIKBKeyplaneView: 0xd59250; frame = (0 0; 320 216); userInteractionEnabled = NO; layer = &amp;lt;CALayer: 0xd59300&amp;gt;&amp;gt; ({{0, 0}, {320, 216}}, (null), #0, 3)&lt;br /&gt;........&amp;lt;UIKBKeyView: 0xd595e0; frame = (1 119; 40 42); opaque = NO; userInteractionEnabled = NO; layer = &amp;lt;CALayer: 0xd596b0&amp;gt;&amp;gt; ({{1, 119}, {40, 42}}, (null), #0, 4)&lt;br /&gt;........&amp;lt;UIKBKeyView: 0xd59af0; frame = (279 119; 40 42); opaque = NO; userInteractionEnabled = NO; layer = &amp;lt;CALayer: 0xd59b60&amp;gt;&amp;gt; ({{279, 119}, {40, 42}}, (null), #0, 4)&lt;br /&gt;........&amp;lt;UIKBKeyView: 0xd59d10; frame = (1 173; 38 42); opaque = NO; userInteractionEnabled = NO; layer = &amp;lt;CALayer: 0xd59d50&amp;gt;&amp;gt; ({{1, 173}, {38, 42}}, (null), #0, 4)&lt;br /&gt;........&amp;lt;UIKBKeyView: 0xd59e20; frame = (41 173; 38 42); opaque = NO; userInteractionEnabled = NO; layer = &amp;lt;CALayer: 0xd59e60&amp;gt;&amp;gt; ({{41, 173}, {38, 42}}, (null), #0, 4)&lt;br /&gt;........&amp;lt;UIKBKeyView: 0xd4dca0; frame = (81 173; 158 42); opaque = NO; userInteractionEnabled = NO; layer = &amp;lt;CALayer: 0xd4dab0&amp;gt;&amp;gt; ({{81, 173}, {158, 42}}, (null), #0, 4)&lt;br /&gt;........&amp;lt;UIKBKeyView: 0xd5bd10; frame = (241 173; 78 42); opaque = NO; userInteractionEnabled = NO; layer = &amp;lt;CALayer: 0xd5bd50&amp;gt;&amp;gt; ({{241, 173}, {78, 42}}, (null), #0, 4)&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In fact, all other keyboards — except the handwriting ones, and emoji also — now uses UIKeyboardLayoutStar to manager the layout. (The old UIKeyboardLayoutRoman is still there.)&lt;br /&gt;&lt;br /&gt;The 6 UIKBKeyView are the special keys, as shown here:&lt;br /&gt;&lt;img src="http://x8c.xanga.com/ee3f5241c0133248344024/w196942468.png" /&gt;&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://pastie.org/535025"&gt;class dump of UIKeyboardLayoutStar&lt;/a&gt; shows some interesting members, e.g. m_keyboardName, m_keyplaneName, the list of dictionaries, etc. Take the &lt;a href="http://picasaweb.google.com/kennytm/IPhoneOS30Keyboards#5315535036383729218"&gt;Arabic keyboard&lt;/a&gt; as example.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;m_keyboardName = @"iPhone-Portrait-Arabic"&lt;/li&gt;&lt;li&gt;m_keyplaneName = @"Letters"&lt;/li&gt;&lt;li&gt;m_states is a dictionary of 35 entries, with keys as UIKBKey to values as NSNumber (integers).&lt;/li&gt;&lt;li&gt;m_keyboard is the keyboard (UIKBKeyboard), which contains a lot of geometry info.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;If we can replace UIKBKeyboard, then we can make our own layout. Where is that UIKBKeyboard set? Looking at the disassembly of UIKit (which is kinda painful now due to its huge size), we see the relevant part is at  -[UIKeyboardLayoutStar setKeyboardName:appearance:]:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;NSString* UIKeyboardGetCurrentInputMode();&lt;br /&gt;NSBundle* UIKeyboardBundleForInputMode(NSString* mode);&lt;br /&gt;NSData* GetKeyboardDataFromBundle(NSString* name, NSBundle* kbbundle);&lt;br /&gt;NSBundle* _UIKitBundle();&lt;br /&gt;UIKBKeyboard* UIKBGetKeyboardByName(NSString* name);&lt;br /&gt;&lt;br /&gt;@implementation UIKeyboardLayoutStar&lt;br /&gt;-(void)setKeyboardName:(NSString*)name appearance:(UIKeyboardAppearance)appr {&lt;br /&gt; UIKBKeyboard* keyboard = [m_keyboards objectForKey:name];&lt;br /&gt; if (keyboard == nil) {&lt;br /&gt;  NSData* keyboardData = GetKeyboardDataFromBundle(name, UIKeyboardBundleForInputMode(UIKeyboardGetCurrentInputMode()));&lt;br /&gt;  if (keyboardData == nil)&lt;br /&gt;   keyboardData = GetKeyboardDataFromBundle(name, _UIKitBundle());&lt;br /&gt;  if (keyboardData != nil) {&lt;br /&gt;   NSKeyedUnarchiver* keyboardArchive = [[NSKeyedUnarchiver alloc] initForReadingWithData:keyboardData];&lt;br /&gt;   keyboard = [keyboardArchive decodeObjectForKey:@"keyboard"];&lt;br /&gt;   [keyboardArchive finishDecoding];&lt;br /&gt;   [keyboardArchive release];&lt;br /&gt;  } else&lt;br /&gt;   keyboard = UIKBGetKeyboardByName(name);&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; if (keyboard == nil)&lt;br /&gt;  return;&lt;br /&gt; &lt;br /&gt; // the rest are not interesting at the moment.&lt;br /&gt;}&lt;br /&gt;@end&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So they defined 3 ways to fetch the UIKBKeyboard, (1) GetKeyboardDataFromBundle from the keyboard bundle (/System/Library/TextInput/TextInput_xx.bundle/), (2) GetKeyboardDataFromBundle from the UIKit bundle, and (3) UIKBGetKeyboardByName.&lt;br /&gt;&lt;br /&gt;What does GetKeyboardDataFromBundle do? Basically,&lt;br /&gt;&lt;pre&gt;GetKeyboardDataFromBundle (name, bundle) {&lt;br /&gt;  Go to the bundle's resource path;&lt;br /&gt;  Open "&lt;name&gt;.keyboard";&lt;br /&gt;  Return the content of this file as NSData*.&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;But there isn't a &lt;em&gt;single&lt;/em&gt; .keyboard file in the TextInput bundles! How about in UIKit.bundle? No, not even one. So the only path taken would be by UIKBGetKeyboardByName. And what does it do? &lt;em&gt;Search from a function table with that name, and call that function&lt;/em&gt;. This probably explain the 70% mass of UIKit — these are functions to define the keyboards. Why they don't use the .keyboard files is a mystery, but from this it seems we can exploit the format to let iKeyEx run on it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-1090528049702072301?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/1090528049702072301/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/07/text-input-on-30-part-1.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/1090528049702072301'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/1090528049702072301'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/07/text-input-on-30-part-1.html' title='Text input on 3.0, Part 1.'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-4626284215753028540</id><published>2009-06-24T02:27:00.003+08:00</published><updated>2009-06-24T02:54:04.466+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GriP'/><title type='text'>GriP 0.1-11n Released</title><content type='html'>GriP 0.1-11n (r344) is released and can be downloaded from &lt;a href="http://code.google.com/p/networkpx/downloads/detail?name=hk.kennytm.grip-0.1-11n.deb"&gt;http://code.google.com/p/networkpx/downloads/detail?name=hk.kennytm.grip-0.1-11n.deb&lt;/a&gt;. This version will be the last revision with Memory Watcher bundled. Starting from next revision, Memory Watcher will be moved to another package. &lt;br /&gt;&lt;br /&gt;GriP 0.1-11n features following changes:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;(r327) GriP will use &lt;a href="http://volatile-dev.com/PreferenceLoader/"&gt;Preference Loader&lt;/a&gt; to inject the preferences. You'll have to install PreferenceLoader first.&lt;/li&gt;&lt;li&gt;(r327) GriP Modal Tables can now be themed.&lt;/li&gt;&lt;li&gt;(r331) All recent GriP messages will be logged.&lt;/li&gt;&lt;li&gt;(r332) The detail disclosure thing (▼) is available in You've Got Mail again.&lt;/li&gt;&lt;li&gt;(r333) Game mode now works in 3.0&lt;/li&gt;&lt;li&gt;(r334) Dismissing the modal table by home button works correctly in 3.0.&lt;/li&gt;&lt;li&gt;(r340) Added Polish localization.&lt;/li&gt;&lt;li&gt;(r343) 3.0 Push notification plug-in.&lt;/li&gt;&lt;li&gt;(As usual) Other bug fixes.&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;Note that if you've downloaded the r341 version that I've uploaded by mistake this morning, you'll experience a memory leak. Please upgrade immediately.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-4626284215753028540?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/4626284215753028540/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/06/grip-01-11n-released.html#comment-form' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/4626284215753028540'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/4626284215753028540'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/06/grip-01-11n-released.html' title='GriP 0.1-11n Released'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-3450108744440632982</id><published>2009-06-23T21:36:00.003+08:00</published><updated>2009-06-24T02:25:00.434+08:00</updated><title type='text'>Sending push notification locally.</title><content type='html'>So far I haven't found a reliable push notification app yet to test GriP Push Notification (QuickPigeon is the most reliable one I've ever tried, but it held up 2 trial mails quite a long time). &lt;br /&gt;&lt;br /&gt;So what about faking push notifications? After a push notification is just a TCP packet. The first thing I do is to set a breakpoint on the most suspicious method -- &lt;code&gt;-[SBRemoteNotificationServer connection:didReceiveMessageForTopic:userInfo:]&lt;/code&gt; (0x9ffa5). And indeed, when a push notification comes, the break point is hit (multiple times).&lt;br /&gt;&lt;br /&gt;I used the breakpoint command&lt;br /&gt;&lt;pre&gt;call (void)CFShow($r2)&lt;br /&gt;call (void)CFShow($r3)&lt;br /&gt;call (void)CFShow(*$sp)&lt;br /&gt;c&lt;/pre&gt;&lt;br /&gt;to record the arguments. And not surprisingly, the userInfo is an NSDictionary of the payload, like&lt;br /&gt;&lt;pre&gt;{&lt;br /&gt;  aps = {&lt;br /&gt;    sound = "hello.aif";&lt;br /&gt;    alert = "Hello world!";&lt;br /&gt;  };&lt;br /&gt;};&lt;/pre&gt;&lt;br /&gt;&lt;a href="http://developer.apple.com/iphone/library/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/ApplePushService/ApplePushService.html"&gt;The Apple's documentation on this&lt;/a&gt; is more in detail. The "topic" parameter is the bundle ID of the app to receive the notification, and connection is an APSConnection object. &lt;br /&gt;&lt;br /&gt;Given these results, we can craft our notification packet with a Mobile Substrate extension.&lt;br /&gt;&lt;br /&gt;Right now, you can download &lt;a href="http://code.google.com/p/networkpx/downloads/detail?name=FakePushNotification.zip"&gt;FakePushNotification.zip&lt;/a&gt; and test it out. To install:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Put the .dylib and the .plist to /Library/MobileSubstrate/DynamicLibraries&lt;/li&gt;&lt;li&gt;Put the executable (FakePushNotification) to /usr/bin and chmod a+x it.&lt;/li&gt;&lt;li&gt;Respring&lt;/li&gt;&lt;li&gt;In command line, type e.g.:&lt;br /&gt;&lt;pre&gt;&lt;b&gt;FakePushNotification com.yourcompany.pushEnabledApp -&lt;/b&gt;&lt;br /&gt;aps={&lt;br /&gt;  alert={&lt;br /&gt;    body = "Hello world!";&lt;br /&gt;    action-loc-key = "Welcome!";&lt;br /&gt;  };&lt;br /&gt;};&lt;br /&gt;^D&lt;/pre&gt;&lt;br /&gt;The "payload" must be in plist format, not JSON format.&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;Note: the program is written to &lt;strong&gt;demonstrate&lt;/strong&gt; how it can be done. It is &lt;strong&gt;not&lt;/strong&gt; bug free. In particular, sending a string that cannot be interpreted as a plist &lt;strong&gt;will cause your device crash and go into safe mode&lt;/strong&gt;. Use with caution.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-3450108744440632982?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/3450108744440632982/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/06/sending-push-notification-locally.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/3450108744440632982'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/3450108744440632982'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/06/sending-push-notification-locally.html' title='Sending push notification locally.'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-1027461068409429496</id><published>2009-06-22T20:33:00.003+08:00</published><updated>2009-06-22T20:46:50.109+08:00</updated><title type='text'>openURL for 3.0 (and 2.x too, probably)</title><content type='html'>openURL is part of &lt;a href="http://ericasadun.com/ftp/EricaUtilities/"&gt;Erica Utilities&lt;/a&gt;. On 3.0, it is not usable anymore because Apple now always throw a "There can only be one UIApplication instance." error &lt;em&gt;even if [UIApplication sharedApplication] still returns nil&lt;/em&gt;. &lt;br /&gt;&lt;br /&gt;But openURL doesn't require UIApplication. The core method, -[UIApplication openURL:] is actually a wrapper of the undocumented function, GSEventSendApplicationOpenURL.&lt;br /&gt;&lt;br /&gt;I've rewritten openURL using GSEventSendApplicationOpenURL, and can be downloaded from &lt;a href="http://code.google.com/p/networkpx/downloads/detail?name=openURL.zip "&gt;http://code.google.com/p/networkpx/downloads/detail?name=openURL.zip&lt;/a&gt;. Note that GSEventSendApplicationOpenURL relies on the Graphics Services private framework, and this framework isn't very stable, so there is a chance it won't work on 4.0.&lt;br /&gt;&lt;br /&gt;You'll notice that there's now a new argument, "port-name". That's actually not quite useful, but I found that it's used in UIKit, so just added it in. (One more reason is that, the function that obtains the default port is renamed in 3.0.) And that piece of UIKit code doesn't work :(.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-1027461068409429496?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/1027461068409429496/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/06/openurl-for-30-and-2x-too-probably.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/1027461068409429496'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/1027461068409429496'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/06/openurl-for-30-and-2x-too-probably.html' title='openURL for 3.0 (and 2.x too, probably)'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-5244946511687422063</id><published>2009-06-22T03:37:00.002+08:00</published><updated>2009-06-22T03:55:50.701+08:00</updated><title type='text'>3.0's presentModalViewController:withTransition:</title><content type='html'>In 3.0 the algorithm -presentModalViewController:animated: is changed. The most prominent change I can see is that the modal view controller will always use the application frame instead of the parent view controller's frame. This breaks modal table theming in GriP. Fortunately, probably Apple also thinks the change to too drastic, they've also provided -_legacyPresentModalViewController:withTransition: that uses the old algorithm, so until iPhoneOS 4.0 comes we can still ignore this problem.&lt;br /&gt;&lt;br /&gt;The 3.0's -presentModalViewController:animated: calls the undocumented method -presentModalViewController:withTransition: as a backend, where the 2nd parameter "transition" is an integer. For official SDK there're 5 official transitions (present and dismiss count as 2): Slide up/down, Flip to left/right, and cross fade.&lt;br /&gt;&lt;br /&gt;But -presentModalViewController:withTransition: supports a bit more:&lt;br /&gt;&lt;table&gt;&lt;tr&gt;&lt;th&gt;Parameter&lt;/th&gt;&lt;th&gt;Transition&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;0&lt;/td&gt;&lt;td&gt;None&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;Push from right to left&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Push from left to right&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;Push from bottom to top&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;6&lt;/td&gt;&lt;td&gt;Fade&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;7&lt;/td&gt;&lt;td&gt;Push from top to bottom&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;8&lt;/td&gt;&lt;td&gt;Slide from bottom to top&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;9&lt;/td&gt;&lt;td&gt;Reveal from top to bottom&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;10&lt;/td&gt;&lt;td&gt;Flip from left to right&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;11&lt;/td&gt;&lt;td&gt;Flip from right to left&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-5244946511687422063?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/5244946511687422063/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/06/30s-presentmodalviewcontrollerwithtrans.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/5244946511687422063'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/5244946511687422063'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/06/30s-presentmodalviewcontrollerwithtrans.html' title='3.0&apos;s presentModalViewController:withTransition:'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-305000890315211138</id><published>2009-06-20T15:58:00.005+08:00</published><updated>2009-08-23T04:25:57.309+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='iKeyEx'/><category scheme='http://www.blogger.com/atom/ns#' term='GriP'/><title type='text'>3.0 Status</title><content type='html'>Updates:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;iKeyEx beta for 3.0 has been out there for weeks. Check the newest posts.&lt;/li&gt;&lt;li&gt;Calculator.searchBundle won't work until someone completely rewrites Spotlight. The guy behind iFile tried to enable custom search bundles before, but the overly-optimized interface made it impossible without rewrites.&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;hr /&gt;&lt;br /&gt;&lt;br /&gt;iPhoneOS 3.0 has been released and jailbroken, and I've also upgraded, so from now on my primary focus of OS will be 3.0, instead of 2.2.1. &lt;br /&gt;&lt;br /&gt;GriP worked pretty well on 3.0. It is predictable as GriP was designed to be as SDK-compatible as much, and I've tested it on 3.0b1 (simulator) from the start.&lt;br /&gt;&lt;br /&gt;But iKeyEx is totally different. It cannot work on 3.0 without in-depth investigation on UIKit again. The primary reason is in 3.0 Apple redesigned a lot in language UI. 80% code of UIKit is about the new keyboard UIKeyboardLayoutStar. The input manager is so heavy that split into its own private framework, TextInput.framework. That carries away UIKeyboardInputManagerAlphabet which iKeyEx relies on.&lt;br /&gt;&lt;br /&gt;iKeyEx will be 3.0-ready, of course, but it will be a long time to wait.&lt;br /&gt;&lt;br /&gt;(And because 3.0 supports single-clipboard copy-and-paste natively, I'll discontinue the current form ℏClipboard. I may write a multi-clipboard extension though.)&lt;br /&gt;&lt;br /&gt;As for the side-projects, Calculator.searchBundle does not work as I expected. I need to check the source code of Search.framework again. And I haven't checked if AdKiller works or not.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-305000890315211138?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/305000890315211138/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/06/30-status.html#comment-form' title='51 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/305000890315211138'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/305000890315211138'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/06/30-status.html' title='3.0 Status'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>51</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-6327611102366254542</id><published>2009-06-07T19:59:00.003+08:00</published><updated>2009-06-07T22:10:57.020+08:00</updated><title type='text'>An incomplete list of entitlement keys</title><content type='html'>&lt;div style="overflow-x: scroll;width:100%;"&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;Key&lt;/th&gt;&lt;th&gt;Type&lt;/th&gt;&lt;th&gt;Used by&lt;/th&gt;&lt;th&gt;Checked by&lt;/th&gt;&lt;th&gt;Notes&lt;br /&gt;&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;com.apple.springboard.debugapplications&lt;/td&gt;&lt;td&gt;boolean&lt;/td&gt;&lt;td&gt;gdb&lt;br /&gt;gdbserver&lt;br /&gt;&lt;/td&gt;&lt;td&gt;SpringBoard:&lt;br /&gt;_SBXXCancelWatchdogAssertionForProcess&lt;br /&gt;_SBXXRenewWatchdogAssertionForProcess&lt;br /&gt;_SBXXAddWatchdogAssertionForProcess&lt;br /&gt;_SBXXLaunchApplicationForDebugging&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;com.apple.springboard.launchapplications&lt;/td&gt;&lt;td&gt;boolean&lt;/td&gt;&lt;td&gt;iapd&lt;br /&gt;Cydia.app&lt;br /&gt;Preferences.app&lt;br /&gt;Web.app&lt;br /&gt;&lt;/td&gt;&lt;td&gt;SpringBoard:&lt;br /&gt;_SBXXLaunchApplicationWithIdentifier&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;com.apple.springboard.opensensitiveurl&lt;/td&gt;&lt;td&gt;boolean&lt;/td&gt;&lt;td&gt;CoreLocation.framework&lt;br /&gt;dataaccessd&lt;br /&gt;ManagedConfiguration.framework&lt;br /&gt;AppStore.app&lt;br /&gt;MobileAddressBook.app&lt;br /&gt;MobileMail.app&lt;br /&gt;MobileMusicPlayer.app&lt;br /&gt;MobileSafari.app&lt;br /&gt;MobileStore.app&lt;br /&gt;Preferences.app&lt;br /&gt;locationd&lt;br /&gt;&lt;/td&gt;&lt;td&gt;SpringBoard:&lt;br /&gt;_SBXXOpenSensitiveURL&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;com.apple.springboard.wipedevice&lt;br /&gt;&lt;/td&gt;&lt;td&gt;boolean&lt;br /&gt;&lt;/td&gt;&lt;td&gt;dataaccessd&lt;br /&gt;Preferences.app&lt;br /&gt;&lt;/td&gt;&lt;td&gt;SpringBoard:&lt;br /&gt;_SBXXDataReset&lt;br /&gt;&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;com.apple.springboard.setnowplayinginformation&lt;br /&gt;&lt;/td&gt;&lt;td&gt;boolean&lt;br /&gt;&lt;/td&gt;&lt;td&gt;YouTube.framework&lt;br /&gt;MobileMail.app&lt;br /&gt;MobileSafari.app&lt;br /&gt;YouTube.app&lt;br /&gt;&lt;/td&gt;&lt;td&gt;?&lt;br /&gt;&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td style="vertical-align: top;"&gt;com.apple.springboard.activateawayviewplugins&lt;br /&gt;&lt;/td&gt;&lt;td style="vertical-align: top;"&gt;boolean&lt;br /&gt;&lt;/td&gt;&lt;td style="vertical-align: top;"&gt;&lt;br /&gt;&lt;/td&gt;&lt;td style="vertical-align: top;"&gt;SpringBoard:&lt;br /&gt;_SBXXEnableLockScreenBundle&lt;br /&gt;&lt;/td&gt;&lt;td style="vertical-align: top;"&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;com.apple.remotenotification.server.preferences&lt;br /&gt;&lt;/td&gt;&lt;td&gt;boolean&lt;br /&gt;&lt;/td&gt;&lt;td&gt;Preferences.app&lt;br /&gt;&lt;/td&gt;&lt;td&gt;SpringBoard:&lt;br /&gt;_SBRNSetBundleIdentifierTypes&lt;br /&gt;&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;get-task-allow&lt;/td&gt;&lt;td&gt;boolean&lt;/td&gt;&lt;td&gt;gdb&lt;br /&gt;gdbserver&lt;br /&gt;&lt;/td&gt;&lt;td&gt;?&lt;/td&gt;&lt;td&gt;The only documented entitlement key, means "Can be debugged".&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;task_for_pid-allow&lt;/td&gt;&lt;td&gt;boolean&lt;/td&gt;&lt;td&gt;ReportCrash&lt;br /&gt;ps&lt;br /&gt;gdb&lt;br /&gt;gdbserver&lt;br /&gt;&lt;/td&gt;&lt;td&gt;kernel&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;keychain-access-groups&lt;/td&gt;&lt;td&gt;array of strings&lt;/td&gt;&lt;td&gt;&lt;span style="font-style: italic;"&gt;Too many&lt;/span&gt;&lt;br /&gt;&lt;/td&gt;&lt;td&gt;?&lt;/td&gt;&lt;td&gt;Everyone uses it has the value (apple).&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;application-identifier&lt;/td&gt;&lt;td&gt;string&lt;/td&gt;&lt;td&gt;&lt;span style="font-style: italic;"&gt;Too many&lt;/span&gt;&lt;br /&gt;&lt;/td&gt;&lt;td&gt;?&lt;/td&gt;&lt;td&gt;The content may not be the same as the bundle ID. For example, the application-identifier for AppStore apps will be (10 random characters).(bundle ID)&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;allow-obliterate-device&lt;/td&gt;&lt;td&gt;boolean&lt;/td&gt;&lt;td&gt;SpringBoard&lt;br /&gt;&lt;/td&gt;&lt;td&gt;?&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;seatbelt-profiles&lt;br /&gt;&lt;/td&gt;&lt;td&gt;array of strings&lt;br /&gt;&lt;/td&gt;&lt;td&gt;MobileMail.app&lt;br /&gt;MobileSafari.app&lt;br /&gt;Web.app&lt;br /&gt;&lt;/td&gt;&lt;td&gt;kernel?&lt;br /&gt;&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;modify-anchor-certificates&lt;br /&gt;&lt;/td&gt;&lt;td&gt;boolean&lt;br /&gt;&lt;/td&gt;&lt;td&gt;Preferences.app&lt;br /&gt;&lt;/td&gt;&lt;td&gt;?&lt;br /&gt;&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;The entitlement of a task can be obtained using the undocumented SecTask*** functions. Because of this, a library can define a set of entitlement keys other applications using it must follow.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-6327611102366254542?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/6327611102366254542/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/06/incomplete-list-of-entitlement-keys.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/6327611102366254542'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/6327611102366254542'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/06/incomplete-list-of-entitlement-keys.html' title='An incomplete list of entitlement keys'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-2593263306863315077</id><published>2009-06-05T03:53:00.002+08:00</published><updated>2009-06-05T04:16:21.271+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GriP'/><title type='text'>GriP 0.1-11m released</title><content type='html'>GriP 0.1-11m (r323) is released, and can be downloaded at &lt;a href="http://code.google.com/p/networkpx/downloads/detail?name=hk.kennytm.grip-0.1-11m.deb"&gt;http://code.google.com/p/networkpx/downloads/detail?name=hk.kennytm.grip-0.1-11m.deb&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The biggest change in 11m is the support for "Modal Table View". You've Got Mail has been modified to support this. The new mail message now looks like:&lt;br /&gt;&lt;img src="http://x16.xanga.com/5a7f407a25735245096609/w194298405.png" /&gt; &lt;br /&gt;Note that the "detail disclosure button" is not there. When you tap on the message a table will pop up:&lt;br /&gt;&lt;img src="http://x4d.xanga.com/ac7f254628633245096605/w194298402.png" /&gt;&lt;br /&gt;You can click on each item to view the message (not as ideal as MobileMail.app, but still readable):&lt;br /&gt;&lt;img src="http://x28.xanga.com/90cf5a7a05735245096608/w194298404.png" /&gt; &lt;br /&gt;&lt;br /&gt;Why is this change? My rationale is that, if you want to show the detail, you are focusing on the message, and stuffing that much information in that message is not good. If you're focusing on it, why not maximize the view? Hence it is shown as a "Modal Table View".&lt;br /&gt;&lt;br /&gt;Does this contradict with the philosophy behind GriP (unobstructive)? No, because this modal thing already has user confirmation, while for alert boxes they just pop up with no prior consent.&lt;br /&gt;&lt;br /&gt;(If you don't like this, you can always downgrade to 0.1-11k available in &lt;a href="http://code.google.com/p/networkpx/downloads/detail?name=hk.kennytm.grip-0.1-11k.deb"&gt;http://code.google.com/p/networkpx/downloads/detail?name=hk.kennytm.grip-0.1-11k.deb&lt;/a&gt;.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-2593263306863315077?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/2593263306863315077/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/06/grip-01-11m-released.html#comment-form' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/2593263306863315077'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/2593263306863315077'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/06/grip-01-11m-released.html' title='GriP 0.1-11m released'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-4110748094619539064</id><published>2009-06-04T23:50:00.005+08:00</published><updated>2009-08-23T03:12:15.378+08:00</updated><title type='text'>Displaying UIView hierarchy of a compiled app</title><content type='html'>Suppose you want to investigate the view hierarchy of some app you did not write. There is a simple way using GDB:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Compile &lt;a href="http://code.google.com/p/networkpx/source/browse/trunk/src/UIKit3/UIUtilities.m"&gt;UIUtilities.m&lt;/a&gt; into a dylib or bundle. You can download it precompiled &lt;a href="http://code.google.com/p/networkpx/downloads/detail?name=UIUtilities.bundle"&gt;here&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;Upload the file to the device, e.g. &lt;tt&gt;/var/mobile/UIUtilities.bundle&lt;/tt&gt;. &lt;em&gt;Do not put it in /var/root/&lt;/em&gt;.&lt;/li&gt;&lt;li&gt;Now attach gdb to the executable you want to investigate.&lt;/li&gt;&lt;li&gt;Inject UIUtilities to the executable. In the gdb prompt, type:&lt;blockquote&gt;&lt;tt&gt;call (int)dlopen("/var/mobile/UIUtilities.bundle", 10)&lt;/tt&gt;&lt;/blockquote&gt;If a nonzero value appears, injection succeeded.&lt;/li&gt;&lt;li&gt;Finally, type:&lt;blockquote&gt;&lt;tt&gt;call (void)UILogViewHierarchy((int)[[UIApplication sharedApplication] keyWindow])&lt;/tt&gt;&lt;/blockquote&gt;The UIView hierarchy of the key window will be recorded in syslog.&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-4110748094619539064?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/4110748094619539064/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/06/displaying-uiview-hierarchy-in-runtime.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/4110748094619539064'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/4110748094619539064'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/06/displaying-uiview-hierarchy-in-runtime.html' title='Displaying UIView hierarchy of a compiled app'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-6818403888827207742</id><published>2009-06-01T18:56:00.003+08:00</published><updated>2009-06-02T02:29:58.202+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='adkiller'/><title type='text'>Testing various Regular Expression solutions, Part 1.5</title><content type='html'>One thing I really like about blogs is that you can exchange ideas and learn something you naturally won't know for a lifetime because you are not an expert. (And I hate you, Xanga Friends Lock users.)&lt;br /&gt;&lt;br /&gt;Firstly, I have added the 3 options &lt;tt&gt;-DNS_BLOCK_ASSERTIONS=1 -DRKL_CACHE_SIZE=307 -DRKL_FAST_MUTABLE_CHECK=1&lt;/tt&gt; as instructed and able to reduce the running time from 1.7s to 0.7s, but still quite slow compared with ICU at 0.25s. Then I increased the cache size to 709, and the running time is now 0.4s. Further increasing to 1619 starts make the running time longer probably due to excessive memory use.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;RKL,307 RKL,709&lt;br /&gt;-------------------&lt;br /&gt;0.691226s 0.384044s&lt;br /&gt;0.692440s 0.381194s&lt;br /&gt;0.684274s 0.381550s&lt;br /&gt;0.689568s 0.382489s&lt;br /&gt;0.683985s 0.384499s&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Then I consider rolling all 16 pattern into one big RegExp like &lt;tt&gt;RE1|RE2|RE3|...&lt;/tt&gt;. One problem with this is each pattern must not have back-references, but this is fine for wildcard rules since back-references do not appear at all. But another nasty thing is that AdBlock Plus rules has the so called filter options which prevents simple merging to take place. Anyway, the running time after merging are:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;ICU       PCRE      regex.h   RKLite    JSRegExp&lt;br /&gt;-------------------------------------------------------------&lt;br /&gt;0.260404s 0.189028s 2.526485s 0.268121s 0.141875s AllInOne&lt;br /&gt;0.256532s 0.160290s 2.526872s 0.264368s 0.141586s&lt;br /&gt;0.257263s 0.160135s 2.536937s 0.266934s 0.142434s&lt;br /&gt;0.256900s 0.160222s 2.532003s 0.265274s 0.141467s&lt;br /&gt;0.256744s 0.160232s 2.528987s 0.264851s 0.142299s&lt;br /&gt;-------------------------------------------------------------&lt;br /&gt;0.253102s 0.067551s 0.235714s 0.382489s 0.113274s SeveralInst (median of 5)&lt;/pre&gt;&lt;br /&gt;So while RegexKitLite does become faster, &lt;em&gt;all other methods are dragged down&lt;/em&gt;, esp. the POSIX ERE. This confirms johne's statement. &lt;br /&gt;&lt;br /&gt;There are some other developments: (1) I've found the &lt;tt&gt;fnmatch&lt;/tt&gt; function that does wildcard matching, but the running time is 0.8s, probably due to the use of recursion and implicit calls on locales. (2) Then I've written a specific routine that checks using pure C string, and the result is dramatic -- the function only takes 0.02 seconds! This restored some of my logical beliefs :D.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;fnmatch5&lt;br /&gt;---------&lt;br /&gt;0.021076s&lt;br /&gt;0.021167s&lt;br /&gt;0.021065s&lt;br /&gt;0.021229s&lt;br /&gt;0.021238s&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The new source code can be found in: &lt;a href="http://pastie.org/496783"&gt;http://pastie.org/496783&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-6818403888827207742?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/6818403888827207742/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/06/testing-various-regular-expression.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/6818403888827207742'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/6818403888827207742'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/06/testing-various-regular-expression.html' title='Testing various Regular Expression solutions, Part 1.5'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-2970984729626756717</id><published>2009-05-31T21:40:00.004+08:00</published><updated>2009-06-02T02:16:19.397+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='adkiller'/><title type='text'>Testing various Regular Expression solutions, Part 1</title><content type='html'>&lt;strong&gt;Edit:&lt;/strong&gt; Please check also &lt;a href="http://networkpx.blogspot.com/2009/06/testing-various-regular-expression.html"&gt;Part 1.5&lt;/a&gt; for some further analysis.&lt;br /&gt;&lt;br /&gt;For AdKiller to work properly, Regular expression matching should be supported. There are various RegExp solutions for the iPhoneOS:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;a href="http://opengroup.org/onlinepubs/007908799/xsh/regex.h.html"&gt;regex.h&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://icu-project.org/apiref/icu4c/uregex_8h.html"&gt;ICU&lt;/a&gt;'s regular expression engine&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.pcre.org/"&gt;PCRE&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://regexkit.sourceforge.net/RegexKitLite/"&gt;RegexKitLite&lt;/a&gt;, which is an ObjC wrapper of the ICU engine.&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.opensource.apple.com/source/JavaScriptCore/JavaScriptCore-466.1.6/pcre/pcre.h"&gt;JavaScriptCore&lt;/a&gt;'s regular expression engine.&lt;li&gt;Do it yourself!&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;For Ad blocking, we only need to test if the Regular Expression matches, so I've limited the test case to a simple RegExp.test only.&lt;br /&gt;&lt;br /&gt;In this part, I'll test for the AdBlockPlus "wildcard rules", where a * matches anything, and optional | at the beginning or end to indicate an anchor. Because of the simplicity, we can actually do the test without using RegExp (e.g. using CFStringFind).&lt;br /&gt;&lt;br /&gt;From the complexity of the RegExp engines, we would expect the time taken follow this order:&lt;br /&gt;&lt;blockquote&gt;CFStringFind &amp;lt;&amp;lt; regex.h &amp;lt;&amp;lt; JSRegExp &amp;lt; ICU &amp;lt; RegexKitLite &amp;lt; PCRE&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-decoration:line-through;color:silver;"&gt;&lt;br /&gt;But somewhat surprisingly, the actual time taken is like this:&lt;br /&gt;&lt;pre&gt;ICU       PCRE      regex.h   RKLite    JSRegExp  CFStrFind&lt;br /&gt;-----------------------------------------------------------&lt;br /&gt;0.253456s 0.069918s 1.726371s 1.651787s 0.139437s 0.078097s&lt;br /&gt;0.275680s 0.067150s 1.715131s 1.652074s 0.112813s 0.075818s&lt;br /&gt;0.251526s 0.067994s 1.716483s 1.637005s 0.113267s 0.075716s&lt;br /&gt;0.250806s 0.067551s 1.721203s 1.626927s 0.113274s 0.075726s&lt;br /&gt;0.251498s 0.067168s 1.716587s 1.651783s 0.113605s 0.076064s&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So the ordering would be:&lt;br /&gt;&lt;blockquote&gt;PCRE &amp;lt; CFStringFind &amp;lt; JSRegExp &amp;lt; ICU &amp;lt;&amp;lt; RegexKitLite &amp;lt; regex.h&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;The most complex engine is the fastest! CFStringFind ranks the second probably because my code is not optimized, but this shows the PCRE engine is really efficient. JSRegExp was originally a PCRE with everything irrelevant to Javascript stripped out, but that is slower than PCRE by 2 times. The WebKit devs should think of what's wrong. RegexKitLite's performance is pretty disappointing. Although it is advertised as very efficient, it is still 6~7 times slower than bare-bone ICU. The problem is probably directly using NSString as the RegExp holder, instead of a dedicated RegExp class. And regex.h's result is really a *WTF*.&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Edit:&lt;/strong&gt; I have redone the test to eliminate some inconsistency (case sensitivity) and convert the regex.h's syntax form BRE to ERE. The result is impressive: ERE is faster than BRE by 7 fold, make in in par with ICU. The new results are:&lt;br /&gt;&lt;pre&gt;Methods&lt;br /&gt;ICU       PCRE      regex.h   RKLite    JSRegExp  CFStrFind&lt;br /&gt;-----------------------------------------------------------&lt;br /&gt;0.253736s 0.069918s 0.238111s 1.651787s 0.139437s 0.070956s&lt;br /&gt;0.254308s 0.067150s 0.235963s 1.652074s 0.112813s 0.068302s&lt;br /&gt;0.252483s 0.067994s 0.235714s 1.637005s 0.113267s 0.068710s&lt;br /&gt;0.251647s 0.067551s 0.234380s 1.626927s 0.113274s 0.068353s&lt;br /&gt;0.253102s 0.067168s 0.235367s 1.651783s 0.113605s 0.068280s&lt;/pre&gt;&lt;br /&gt;and the new ordering is:&lt;br /&gt;&lt;blockquote&gt;PCRE &amp;asymp; CFStringFind &amp;lt; JSRegExp &amp;lt; regex.h &amp;lt; ICU &amp;lt;&amp;lt; RegexKitLite&lt;/blockquote&gt;&lt;br /&gt;So PCRE is still the fastest, but with a smaller margin. And RegexKitLite is now win the title of the slowest RegEx implementation.&lt;br /&gt;&lt;br /&gt;To conclude this part, &lt;strong&gt;we should use PCRE for wildcard testing&lt;/strong&gt;, if speed and clarity are important.&lt;br /&gt;&lt;br /&gt;The source code of the test can be found in &lt;a href="http://pastie.org/495990"&gt;http://pastie.org/495990&lt;/a&gt;. Basically, 323 URLs collected from 3 different sources are matched against 16 wildcard rules. The file is compiled with:&lt;br /&gt;&lt;code&gt;/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/gcc-4.0 -arch armv6 -std=c99 -isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.2.1.sdk -I/Developer/Platforms/iPhoneOS.platform/Developer/usr/include/gcc/darwin/default -I/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.2.1.sdk/usr/lib/gcc/arm-apple-darwin9/4.0.1/include -L/usr/local/lib -Wall -mcpu=arm1176jzf-s -O2 -L. -framework CoreFoundation -framework Foundation -licucore -lpcre main.m RegexKitLite.m ; ldid -S a.out&lt;/code&gt;&lt;br /&gt;and run on a jailbroken iPod Touch 1G, firmware version 2.2.1.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-2970984729626756717?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/2970984729626756717/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/05/testing-various-regular-expression.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/2970984729626756717'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/2970984729626756717'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/05/testing-various-regular-expression.html' title='Testing various Regular Expression solutions, Part 1'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-5568334607690346887</id><published>2009-05-29T07:02:00.005+08:00</published><updated>2009-05-29T07:18:42.101+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='adkiller'/><title type='text'>Introducing Ad Killer</title><content type='html'>This is a short MS extension I've coded up as a direct respond to Greystripe's intrusive advertisement. (How intrusive it is? Download CubesFree and you'll know. C'mon, why not use AdMob?)&lt;br /&gt;&lt;br /&gt;Ad Killer is a simple extension that hooks on the NSURLConnection class. It checks the URL against known criteria, and if it is determined as an Ad (or a bad site, whatever), it will convert the URL to a bad site that will always fail the request.&lt;br /&gt;&lt;br /&gt;Unlike methods using .hosts, Ad Killer has the potential to support Regular Expressions, and thus AdBlock Plus filters (except element blocking). And unlike AdBlock by CocoaMug, it can work with almost all applications* (not just MobileSafari) and it is free.&lt;br /&gt;&lt;br /&gt;Currently Ad Killer is not packaged for release, but you can check out the code at &lt;a href="http://code.google.com/p/networkpx/source/browse/trunk/hk.kennytm.adkiller"&gt;http://code.google.com/p/networkpx/source/browse/trunk/hk.kennytm.adkiller&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;*: AdKiller will not work on Cydia, or any setuid apps that does not support MobileSubstrate.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-5568334607690346887?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/5568334607690346887/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/05/introducing-ad-killer.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/5568334607690346887'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/5568334607690346887'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/05/introducing-ad-killer.html' title='Introducing Ad Killer'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-5954662358877692764</id><published>2009-05-28T22:51:00.002+08:00</published><updated>2009-05-29T00:25:28.445+08:00</updated><title type='text'>An application that SpringBoard is not tracking just launched with identifier ... and will be killed.</title><content type='html'>If you directly run a UIKit app from command line, nothing will be shown, and the syslog will print:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;An application that SpringBoard is not tracking just launched with identifier com.yourcompany.Untitled and will be killed.&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Why? If you disassemble SpringBoard with thumb-ddis, you can quickly found this string is referred in the function 0x123ba. This function is called only from -[SpringBoard applicationStarted:], decompiled as:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;@implementation SpringBoard&lt;br /&gt;-(void)applicationStarted:(GSEventRef)event { _123ba(event); }&lt;br /&gt;@end&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;So it is pretty easy to get the signature and purpose of this function. 0x123ba decompiled is roughly like:&lt;br /&gt;&lt;pre&gt;void LaunchApplication (GSEventRef event) {&lt;br /&gt; GSEventRecord* pRecord = _GSEventGetGSEventRecord(event);&lt;br /&gt;&lt;br /&gt; struct GSEventAppLaunch {&lt;br /&gt;  pid_t       pid;   // 48&lt;br /&gt;  void*       m_52;   // 52&lt;br /&gt;  const char  displayIdentifier[]; // 56&lt;br /&gt; }* pAppRecord = pRecord + 1;&lt;br /&gt;&lt;br /&gt; if (getpid() != pAppRecord-&gt;pid) {&lt;br /&gt;  // call 11fc8&lt;br /&gt;  NSString* displayIdentifier = NSStringCreateWithUTF8String(pAppRecord-&gt;displayIdentifier, pRecord-&gt;size - 8);&lt;br /&gt;  if (displayIdentifier != nil) {&lt;br /&gt;   // call 107d8&lt;br /&gt;   SBApplication* app = SBApplicationGetWithDisplayIdentifier(displayIdentifier);&lt;br /&gt;   // 123e8&lt;br /&gt;   if (app != nil) {&lt;br /&gt;    [app sendActivationEvent:event];&lt;br /&gt;    [displayIdentifier release];&lt;br /&gt;    return;&lt;br /&gt;   }&lt;br /&gt;  }&lt;br /&gt;  // 123fa&lt;br /&gt;  NSLog(@"An application that SpringBoard is not tracking just launched with identifier %@ and will be killed.", displayIdentifier);&lt;br /&gt;  kill(pAppRecord-&gt;pid, 9);&lt;br /&gt;  [displayIdentifier release];&lt;br /&gt; }&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Since we are getting prompt of the display ID there is no reason the condition &lt;code&gt;displayIdentifier != nil&lt;/code&gt; will fail, so it must be due to &lt;code&gt;app == nil&lt;/code&gt;. We can set a break point at 0x123e8, and indeed, it returns nil. But having the same argument, why one returns a valid object and one returns nil? There must be some global variables it relies on. Let's take a look at 0x107d8 to be sure.&lt;br /&gt;&lt;br /&gt;The function 0x107d8 roughly translates to:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;SBApplication* SBApplicationGetWithDisplayIdentifier(NSString* identifier) { return _106a0(DisplayStack_e7004, identifier) ?: _106a0(DisplayStack_e7014, identifier) ?: _106a0(DisplayStack_e7008, identifier); }&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The DisplayStack_xxx are instances of SBDisplayStack. In this context, SBDisplayStack is like an array of SBApplication, and the function 0x106a0 merely search for an SBApplication having the specified identifier from the stack. So what we are checking is already an aftereffect. &lt;br /&gt;&lt;br /&gt;(more about Display stack: &lt;a href="http://code.google.com/p/iphone-tweaks/wiki/DevelopmentNotes"&gt;http://code.google.com/p/iphone-tweaks/wiki/DevelopmentNotes&lt;/a&gt;)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-5954662358877692764?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/5954662358877692764/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/05/application-that-springboard-is-not.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/5954662358877692764'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/5954662358877692764'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/05/application-that-springboard-is-not.html' title='An application that SpringBoard is not tracking just launched with identifier ... and will be killed.'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-5367549665254464800</id><published>2009-05-26T22:54:00.004+08:00</published><updated>2009-05-26T23:25:08.797+08:00</updated><title type='text'>Just for fun: Some undocumented flags of ldid</title><content type='html'>&lt;tt&gt;ldid&lt;/tt&gt; was used most commonly to pseudosign an app, so that it would run in a jailbroken device. It is also used to attach an entitlement file to an executable. But besides the well-known -S (pseudosign/add entitlement) and less-well-known -e (dump entitlement) flag, there are a couple of flags went undocumented.&lt;br /&gt;&lt;br /&gt;&lt;table border="1"&gt;&lt;tr&gt;&lt;th&gt;-p &amp;lt;Files&amp;gt;&lt;/th&gt;&lt;td&gt;Print the paths of the input files.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th&gt;-u &amp;lt;Files&amp;gt;&lt;/th&gt;&lt;td&gt;Print the UUID of the input files.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th&gt;-t &amp;lt;Files&amp;gt;&lt;/th&gt;&lt;td&gt;Print the &lt;a href="http://developer.apple.com/documentation/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html#//apple_ref/doc/c_ref/dylib"&gt;timestamp&lt;/a&gt; of a dylib.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th&gt;-T&amp;lt;NewTimestamp&amp;gt; &amp;lt;Files&amp;gt;&lt;/th&gt;&lt;td&gt;Assign the timestamp of a dylib. Pass "-" to &amp;lt;NewTimestamp&amp;gt; to assign the timestamp to a hash.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;th&gt;-s&lt;/th&gt;&lt;td&gt;Calculate the sha1 without changing anything. Incompatible with the -S flag.&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-5367549665254464800?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/5367549665254464800/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/05/just-for-fun-some-undocumented-flags-of.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/5367549665254464800'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/5367549665254464800'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/05/just-for-fun-some-undocumented-flags-of.html' title='Just for fun: Some undocumented flags of ldid'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-5167965002534516106</id><published>2009-05-21T22:50:00.002+08:00</published><updated>2009-05-29T09:07:09.425+08:00</updated><title type='text'>Experiment: An alternative way to extract hidden symbols</title><content type='html'>A library usually have &lt;i&gt;symbols&lt;/i&gt; defined functions and variables to allow external code access its functions, or help debugging. There are external (public) and hidden symbols. The external symbols can be picked up by &lt;tt&gt;dyld&lt;/tt&gt; to broadcast the correct place of the functions. The hidden ones will be ignored, however, for performance reasons, or just to hide some interesting calls.&lt;br /&gt;&lt;br /&gt;And the hidden ones are often interesting. For example, &lt;a href="http://svn.saurik.com/repos/menes/trunk/winterboard/Library.mm"&gt;WinterBoard&lt;/a&gt; needed 7 hidden symbols to work.&lt;br /&gt;&lt;br /&gt;Fortunately, the address each symbol points to, hidden or not, is defined alongside the library, so one can read the library file to get all the symbols.&lt;br /&gt;&lt;br /&gt;In fact, Apple provided the &lt;tt&gt;nlist&lt;/tt&gt; function for this purpose. But &lt;tt&gt;nlist&lt;/tt&gt; is &lt;em&gt;sloooooow&lt;/em&gt;. So slow that saurik has improved the backend of &lt;a href="http://svn.saurik.com/repos/menes/trunk/mobilesubstrate/nlist.c"&gt;nlist&lt;/a&gt; the next version of MobileSubstrate (which delivered more than 10 times speed improvement.)&lt;br /&gt;&lt;br /&gt;But how did I step in this? Originally I tried to create a transition filter for QuartzCore. This requires me to access the C++ backend of the QC, which are all hidden symbols. So I use &lt;tt&gt;nlist&lt;/tt&gt; as usual. And I've written a wrapper function using va_arg to make it simpler to use. Then it crashed. Why? There's one caveat — on x86 the QuartzCore is &lt;em&gt;slided&lt;/em&gt;. The address returned from &lt;tt&gt;nlist&lt;/tt&gt; — which is just being read statically — is &lt;em&gt;invalid&lt;/em&gt; because a &lt;em&gt;run-time&lt;/em&gt; offset must be added to it.&lt;br /&gt;&lt;br /&gt;This slide can be obtained using the dyld function &lt;tt&gt;_dyld_get_image_vmaddr_slide&lt;/tt&gt;. But it takes an integer! What integer? This is an &lt;em&gt;index&lt;/em&gt; of all images loaded by dyld. To check which image it is pointed to, one needs to call &lt;tt&gt;_dyld_get_image_name&lt;/tt&gt;. That's troublesome, and adds extra slowness to the &lt;tt&gt;nlist&lt;/tt&gt; method.&lt;br /&gt;&lt;br /&gt;But there's also a &lt;tt&gt;_dyld_get_image_header&lt;/tt&gt; function. This function returns the Mach-O header, which can guide you to do the same thing nlist does, but on the &lt;tt&gt;loaded image&lt;/tt&gt;. Because it is loaded, every read/write will be on the RAM, and it will be much faster than file access. That's good! Except it crashed again — the loaded image is not a direct copy-and-paste. Some part (the __DATA, __OBJC and __IMPORT segments, to be precise) are skipped from the object file. &lt;em&gt;And&lt;/em&gt; the same solution for treating QuartzCore cannot be used on UIKit.&lt;br /&gt;&lt;br /&gt;So I started to dig the source code of dyld, which I found that these 3 APIs are just C wrapper to a various (i.e. hidden) C++ function. The function, &lt;tt&gt;dyld::getIndexedImage&lt;/tt&gt;, returns a class pointer that has &lt;em&gt;everything&lt;/em&gt; I need. Everything. It has the symbol table, the strings table, and the Mach-O header, and that's enough for exploring hidden symbols.&lt;br /&gt;&lt;br /&gt;Of course, since &lt;tt&gt;dyld::getIndexedImage&lt;/tt&gt; is hidden, to call it we need to &lt;tt&gt;nlist&lt;/tt&gt; it too... Or not. saurik has already shown that rewriting &lt;tt&gt;nlist&lt;/tt&gt; improves the speed by 10x, why not do it here also? The result, therefore, is this monster:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://pastie.org/485348"&gt;http://pastie.org/485348&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;It has been tested and works on ARM &lt;em&gt;and&lt;/em&gt; i386. Experimentally, running the &lt;tt&gt;main()&lt;/tt&gt; function gives the timing in 5 runs:&lt;br /&gt;&lt;br /&gt;&lt;table border="1" width="50%"&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;nlist&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;lookup_function_pointers&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;0.517996s&lt;/td&gt;&lt;td&gt;0.026339s&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;0.498724s&lt;/td&gt;&lt;td&gt;0.013721s&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;0.498352s&lt;/td&gt;&lt;td&gt;0.013623s&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;0.501114s&lt;/td&gt;&lt;td&gt;0.013798s&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;0.498718s&lt;/td&gt;&lt;td&gt;0.015770s&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;So my method gives up to &lt;strong&gt;30x&lt;/strong&gt; performance than nlist! I'm happy to include saurik's nlist fix too, but it Bus Errored on &lt;tt&gt;strcmp&lt;/tt&gt; too many times that I've gave up on that. Hopefully later it will be fixed.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-5167965002534516106?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/5167965002534516106/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/05/experiment-alternative-way-to-extract.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/5167965002534516106'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/5167965002534516106'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/05/experiment-alternative-way-to-extract.html' title='Experiment: An alternative way to extract hidden symbols'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-7581711649352460935</id><published>2009-05-09T16:02:00.003+08:00</published><updated>2009-05-09T19:46:56.897+08:00</updated><title type='text'>Banning SCHelper from syslog</title><content type='html'>&lt;i&gt;(&lt;a href="#schelper_summary"&gt;Here&lt;/a&gt; is the necessary change required, for 2.2.1, if you don't bother to read.)&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;(Make sure you back up every file you want to change first. We won't take responsibility for your broken devices :p)&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;tt&gt;syslog&lt;/tt&gt; is a very useful tool for watching variables and monitoring &lt;br /&gt;system status. But &lt;i&gt;SCHelper&lt;/i&gt; make it particular troublesome to follow the messages.&lt;br /&gt;&lt;br /&gt;SCHelper stands to &lt;i&gt;System Configuration Helper&lt;/i&gt;, and it manages the &lt;tt&gt;NSUserDefaults&lt;/tt&gt; writes. In regular interval SCHelper will synchronize the NSUserDefaults on RAM to the harddisk, and report it in &lt;tt&gt;syslog&lt;/tt&gt;. The problem is, the report takes 7 to 13 lines, and is completely useless to know:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;May  9 15:55:16 --- SCHelper[1491]: per-session socket : invalidate fd 9&lt;br /&gt;May  9 15:55:21 --- SCHelper[1491]: processing command "AUTH" w/data&lt;br /&gt;May  9 15:55:21 --- SCHelper[1491]: sending status 0&lt;br /&gt;May  9 15:55:21 --- SCHelper[1491]: processing command "PREFS open" w/data&lt;br /&gt;May  9 15:55:21 --- SCHelper[1491]: sending status 0&lt;br /&gt;May  9 15:55:21 --- SCHelper[1491]: processing command "PREFS lock/wait"&lt;br /&gt;May  9 15:55:21 --- SCHelper[1491]: sending status 0&lt;br /&gt;May  9 15:55:21 --- SCHelper[1491]: processing command "PREFS commit" w/data&lt;br /&gt;May  9 15:55:21 --- SCHelper[1491]: sending status 0 w/reply&lt;br /&gt;May  9 15:55:21 --- SCHelper[1491]: processing command "PREFS unlock"&lt;br /&gt;May  9 15:55:21 --- SCHelper[1491]: sending status 0&lt;br /&gt;May  9 15:55:21 --- SCHelper[1491]: processing command "PREFS close"&lt;br /&gt;May  9 15:55:21 --- SCHelper[1491]: processing command "EXIT"&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Usually one watches the syslog using &lt;tt&gt;tail -f /var/log/syslog&lt;/tt&gt;. When SCHelper is in action, suddenly a dozen lines come up and you may miss what you need to know. (Of course you can filter the result using &lt;tt&gt;grep&lt;/tt&gt;, but it's just pretending the problem does not exist.)&lt;br /&gt;&lt;br /&gt;To solve the root cause we need to disable SCHelper from yelling. A starting point is to disassemble &lt;tt&gt;SCHelper&lt;/tt&gt;. The file is located at &lt;tt&gt;/System/Library/Frameworks/SystemConfiguration.framework/SCHelper&lt;/tt&gt;. We can search for the keyword &lt;tt&gt;processing command&lt;/tt&gt; in the disassembly, and these line should come up:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt; +00104 000023c4 0100A0E3             mov               r0,#0x1&lt;br /&gt; +00108 000023c8 0710A0E3             mov               r1,#0x7&lt;br /&gt; +0010c 000023cc 98219FE5             ldr               r2,[pc,#0x198]                    ; -&gt; 0x256c CFSTR("processing command \"%s\"%s")&lt;br /&gt; +00110 000023d0 960100EB             bl                SCLog (stub)&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;This is equivalent to the call &lt;tt&gt;SCLog(1, 7, CFSTR("processing command \"%s\"%s"), &amp;lt;other arguments&amp;gt;)&lt;/tt&gt;. What, &lt;a href="http://developer.apple.com/DOCUMENTATION/Cocoa/Reference/Foundation/Miscellaneous/Foundation_Functions/Reference/reference.html#//apple_ref/c/func/NSLog"&gt;yet&lt;/a&gt; &lt;a href="http://developer.apple.com/documentation/CoreFoundation/Reference/CFTypeRef/Reference/reference.html#//apple_ref/c/func/CFShow"&gt;another&lt;/a&gt; &lt;a href="http://networkpx.blogspot.com/2009/05/introducing-cflog.html"&gt;Log&lt;/a&gt; &lt;a href="http://blogs.oreilly.com/digitalmedia/2008/02/gslog-another-way-to-log.html"&gt;function&lt;/a&gt;? Hell yes.&lt;br /&gt;&lt;br /&gt;This SCLog is an external symbol. We can play a dirty trick to transform all &lt;tt&gt;SCLog&lt;/tt&gt; into &lt;a href="http://opengroup.org/onlinepubs/007908775/xsh/ilogb.html"&gt;&lt;tt&gt;ilogb&lt;/tt&gt;&lt;/a&gt; :p. We need to edit the link table for this. The first obvious step is to search for the string &lt;tt&gt;_SCLog&lt;/tt&gt; and replace it to &lt;tt&gt;_ilogb&lt;/tt&gt; (or your favorite pure function). But this will make &lt;tt&gt;dyld&lt;/tt&gt; complain not finding &lt;tt&gt;_ilogb&lt;/tt&gt; in &lt;tt&gt;SystemConfiguration&lt;/tt&gt; (&lt;tt&gt;_ilogb&lt;/tt&gt; is in &lt;tt&gt;libSystem.B.dylib&lt;/tt&gt;). We must change the dylib referenced by this particular symbol as well. &lt;br /&gt;&lt;br /&gt;How dyld searches identify a stub symbol? From the &lt;a href="http://developer.apple.com/DOCUMENTATION/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html"&gt;Mach-O ABI&lt;/a&gt;, we can see it involves a lot of indirection:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Obtain the &lt;i&gt;indirect symbol table&lt;/i&gt; from the &lt;i&gt;dynamic symbol table&lt;/i&gt; (&lt;tt&gt;LC_DYSYMTAB&lt;/tt&gt; load command)&lt;/li&gt;&lt;li&gt;Every entry of the indirect symbol table points to an index of the &lt;i&gt;symbol table&lt;/i&gt; (&lt;tt&gt;LC_SYMTAB&lt;/tt&gt; load command)&lt;/li&gt;&lt;li&gt;An entry of a symbol table is better known as &lt;tt&gt;nlist&lt;/tt&gt;. In our case, the &lt;tt&gt;nlist&lt;/tt&gt; contains reference to the &lt;i&gt;dylib&lt;/i&gt; (an &lt;tt&gt;LC_LOAD_DYLIB&lt;/tt&gt; load command) and an offset in the &lt;i&gt;string table&lt;/i&gt;.&lt;/li&gt;&lt;li&gt;Finally from the string table we get the actual C string.&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;What we get is the offset of the C string, &lt;tt&gt;_SCLog&lt;/tt&gt;. We can go up 1 level from there (to the nlist), and modify the dylib it references, then it should work.&lt;br /&gt;&lt;br /&gt;For this task, &lt;tt&gt;otool&lt;/tt&gt; and &lt;tt&gt;nm&lt;/tt&gt; is of great help.&lt;br /&gt;&lt;br /&gt;Using &lt;tt&gt;otool -L SCHelper&lt;/tt&gt; we can see that the string table (&lt;tt&gt;LC_SYMTAB&lt;/tt&gt;'s &lt;tt&gt;stroff&lt;/tt&gt;) is at file offset 15024 (0x3ab0). Additional, the file offset of the string &lt;tt&gt;_SCLog&lt;/tt&gt; is at 0x3cd0. Therefore, the string table offset is 0x3cd0 - 0x3ab0 = 0x220.&lt;br /&gt;&lt;br /&gt;Then, in the same load command we can find the symbol table's file offset  (&lt;tt&gt;symoff&lt;/tt&gt;) is 12832 (0x3220).&lt;br /&gt;&lt;br /&gt;Now, to quickly search for a symbol, we use &lt;tt&gt;nm -p SCHelper | nl -v 0&lt;/tt&gt;. (The -p flags tells &lt;tt&gt;nm&lt;/tt&gt; don't try to sort the symbol table, and the &lt;tt&gt;nl&lt;/tt&gt; part is a &lt;a href="http://en.wikipedia.org/wiki/Nl_%28Unix%29"&gt;Unix utility for line numbering&lt;/a&gt;.) We can find &lt;tt&gt;_SCLog&lt;/tt&gt; at 67, meaning we should be able to find the &lt;tt&gt;nlist&lt;/tt&gt; of &lt;tt&gt;_SCLog&lt;/tt&gt; at (0x3220 + 67 * sizeof(struct nlist) = 0x3544).&lt;br /&gt;&lt;br /&gt;So let's proceed to 0x3544. The structure of nlist, for our concern is&lt;br /&gt;&lt;code&gt;struct nlist {&lt;br /&gt;  int  symbol_index;&lt;br /&gt;  char lets_not_bother_it_its_always_0x0D;&lt;br /&gt;  char lets_not_bother_it_its_always_zero;&lt;br /&gt;  char lets_not_bother_it_its_always_0x01;&lt;br /&gt;  char the_dylib;&lt;br /&gt;  void* the_vm_address_that_we_dont_care;&lt;br /&gt;};&lt;/code&gt;We can verify the first 4 bytes are indeed 0x220, so this is the correct address. For &lt;tt&gt;_SCLog&lt;/tt&gt;, &lt;tt&gt;the_dylib&lt;/tt&gt; = 2, and the dylib referenced are, in order:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation&lt;/li&gt;&lt;li&gt;&lt;b&gt;/System/Library/Frameworks/SystemConfiguration.framework/SystemConfiguration&lt;/b&gt;&lt;/li&gt;&lt;li&gt;/System/Library/Frameworks/Security.framework/Security&lt;/li&gt;&lt;li&gt;/usr/lib/libgcc_s.1.dylib&lt;/li&gt;&lt;li&gt;/usr/lib/libSystem.B.dylib&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;so we should change the 2 into 5.&lt;br /&gt;&lt;br /&gt;I believe there is some link editor that doesn't require us to jump so many hoops. If you know, please leave a comment :).&lt;br /&gt;&lt;br /&gt;In summary, the changes are (if you are using 2.2.1):&lt;br /&gt;&lt;ol id="schelper_summary"&gt;&lt;li&gt;Open SCHelper with a hex editor.&lt;/li&gt;&lt;li&gt;Head to 0x354B, change the 02 to 05&lt;/li&gt;&lt;li&gt;Search for the string "SCLog", replace it with "ilogb".&lt;/li&gt;&lt;li&gt;Save, and of course, ldid it.&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;Now respring, and &lt;tt&gt;ps -A&lt;/tt&gt;. Is &lt;tt&gt;SCHelper&lt;/tt&gt; running? Yes, great. Does it emit useless &lt;tt&gt;syslog&lt;/tt&gt; entries anymore? No, it's busy computing logarithms instead :p. Now launch Settings, fiddle with anything. Does it save? Yes, fantastic.&lt;br /&gt;&lt;br /&gt;So our task succeeded. Note that if you are using any versions other than 2.2.1, the file offsets may be different.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-7581711649352460935?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/7581711649352460935/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/05/banning-schelper-from-syslog.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/7581711649352460935'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/7581711649352460935'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/05/banning-schelper-from-syslog.html' title='Banning SCHelper from syslog'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-3634063537793337261</id><published>2009-05-05T15:14:00.003+08:00</published><updated>2009-05-05T15:32:28.123+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GriP'/><title type='text'>GriP 0.1-11j released</title><content type='html'>This version introduced a lot of features since 0.1-11e (well you see there are 5 private development versions in between, the change is pretty a lot). &lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Game mode&lt;/strong&gt; – Suspend GriP in certain applications.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Screen On/Off detection&lt;/strong&gt; – Hold important messages when the screen is off, and show them all when the screen is on again.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Multi-column support&lt;/strong&gt; – Basically, you can fill a whole screen of GriP messages where you could only fill half before :p&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Theme customization&lt;/strong&gt; – Currently you can only change the width of the Default theme, but the framework is completely general.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;For developers, GriP now supports using &lt;strong&gt;Emoji as icon&lt;/strong&gt;. For theme makers, the max width of the GriP message window can be queried using `+[GPMessageWindow maxWidth]`. The background colors of the window can be modified with `+[GPMessageWindow setBackgroundColor:]`, if you don't like to do that yourself.&lt;br /&gt;&lt;br /&gt;You can download at &lt;a href="http://code.google.com/p/networkpx/downloads/list"&gt;http://code.google.com/p/networkpx/downloads/list&lt;/a&gt; as usual.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-3634063537793337261?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/3634063537793337261/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/05/grip-01-11j-released.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/3634063537793337261'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/3634063537793337261'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/05/grip-01-11j-released.html' title='GriP 0.1-11j released'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-8186941521278294212</id><published>2009-05-02T04:00:00.006+08:00</published><updated>2009-05-02T04:18:16.805+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='CoreFoundation'/><title type='text'>Introducing CFLog</title><content type='html'>In Foundation, there is a very handy printf-like function for debugging, called &lt;tt&gt;NSLog&lt;/tt&gt;. You can call it like this:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;NSLog(@"%@'s temperature is %f K", [NSDate date], 310.f);&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;In CoreFoundation, however, there is just a single-argument &lt;tt&gt;CFShow&lt;/tt&gt;. This forces the simple NSLog line split into 3:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;CFStringRef debugString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@'s temperature is %f K"), [NSDate date], 310.f);&lt;br /&gt;CFShow(debugString);&lt;br /&gt;CFRelease(debugString);&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;This is very annoying when you have lots of code like these. Of course we can always define a macro or function to take out all the repeating parts, e.g. in &lt;a href="http://svn.saurik.com/repos/menes/trunk/mobilesubstrate/MobileLoader.mm"&gt;MobileSubstrate's source code&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;#define CFLog(args...) \&lt;br /&gt;    do { \&lt;br /&gt;        CFStringRef string(CFStringCreateWithFormat(kCFAllocatorDefault, NULL, args)); \&lt;br /&gt;        CFShow(string); \&lt;br /&gt;        CFRelease(string); \&lt;br /&gt;    } while(0)&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;But there is actually a more powerful &lt;tt&gt;CFLog&lt;/tt&gt; built into CoreFoundation. It is, unsurprisingly, called &lt;tt&gt;CFLog&lt;/tt&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;/*&lt;br /&gt;        APPLE SPI:  NOT TO BE USED OUTSIDE APPLE!&lt;br /&gt;*/&lt;br /&gt;&lt;br /&gt;enum { // Legal level values for CFLog()&lt;br /&gt;    kCFLogLevelEmergency = 0,&lt;br /&gt;    kCFLogLevelAlert = 1,&lt;br /&gt;    kCFLogLevelCritical = 2,&lt;br /&gt;    kCFLogLevelError = 3,&lt;br /&gt;    kCFLogLevelWarning = 4,&lt;br /&gt;    kCFLogLevelNotice = 5,&lt;br /&gt;    kCFLogLevelInfo = 6,&lt;br /&gt;    kCFLogLevelDebug = 7,&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;CF_EXPORT void CFLog(int32_t level, CFStringRef format, ...);&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The header code can be found in &lt;a href="http://www.opensource.apple.com/darwinsource/10.5.6/CF-476.17/CFLogUtilities.h"&gt;http://www.opensource.apple.com/darwinsource/10.5.6/CF-476.17/CFLogUtilities.h&lt;/a&gt; (requires login). This is available on the iPhoneOS too as an undocumented function &lt;strong&gt;starting from 2.2&lt;/strong&gt;. So you can now do it like this instead:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;CFLog(kCFLogLevelDebug, CFSTR("%@'s temperature is %f K"), [NSDate date], 310.f);&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Simple and beautiful.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-8186941521278294212?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/8186941521278294212/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/05/introducing-cflog.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/8186941521278294212'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/8186941521278294212'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/05/introducing-cflog.html' title='Introducing CFLog'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-1860754953923015388</id><published>2009-04-24T11:28:00.004+08:00</published><updated>2009-04-25T02:33:07.741+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GriP'/><title type='text'>GriP (Growl for iPhone) is in beta now.</title><content type='html'>Let me cut it short: you can download GriP 0.1-11b (beta) from &lt;a href="http://code.google.com/p/networkpx/downloads/detail?name=hk.kennytm.grip-0.1-11a.deb"&gt;http://code.google.com/p/networkpx/downloads/detail?name=hk.kennytm.grip-0.1-11b.deb&lt;/a&gt; now. The documentation is also available in &lt;a href="http://code.google.com/p/networkpx/wiki/GriP"&gt;http://code.google.com/p/networkpx/wiki/GriP&lt;/a&gt;, which contains most thing you are interested. It should run flawlessly on a jailbroken 3.x device too, but I haven't tested (I don't have a 3.x device right now).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-1860754953923015388?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/1860754953923015388/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/04/grip-growl-for-iphone-is-in-beta-now.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/1860754953923015388'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/1860754953923015388'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/04/grip-growl-for-iphone-is-in-beta-now.html' title='GriP (Growl for iPhone) is in beta now.'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-6680831093530032418</id><published>2009-04-05T02:08:00.003+08:00</published><updated>2009-04-05T04:44:32.230+08:00</updated><title type='text'>self notes...</title><content type='html'>[UIFont smallSystemFontSize] == 12&lt;br /&gt;[UIFont systemFontSize] == 14&lt;br /&gt;[UIFont labelFontSize] == 17&lt;br /&gt;[UIFont buttonFontSize] == 18&lt;br /&gt;&lt;br /&gt;Default font size of Rounded Rect button == 15&lt;br /&gt;Default font size of UITextField == 12&lt;br /&gt;&lt;br /&gt;&lt;img src="http://1.bp.blogspot.com/_7Ek7e48Yovg/SdfGmR1S6lI/AAAAAAAAAHk/Qez6IQAXbYo/s320/Untitled+Image.png" /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-6680831093530032418?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/6680831093530032418/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/04/self-notes.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/6680831093530032418'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/6680831093530032418'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/04/self-notes.html' title='self notes...'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_7Ek7e48Yovg/SdfGmR1S6lI/AAAAAAAAAHk/Qez6IQAXbYo/s72-c/Untitled+Image.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-5776863138478048302</id><published>2009-03-31T00:52:00.003+08:00</published><updated>2009-03-31T01:50:38.229+08:00</updated><title type='text'>Releases: Thumb Dumb Disassembler &amp; Calculator.searchBundle</title><content type='html'>Last few weeks I've diverted myself from iKeyEx to the 3.0 VFDecrypt key. The result? Of course it's failure, otherwise you'll see the key on theiphonewiki right now. &lt;br /&gt;&lt;br /&gt;But a nice by-product is the "Thumb Dumb Disassembler". For iPhone reverse engineering, if the code is compiled to ARM then ravel-arm can be used to give very useful information. However, if it is compiled to Thumb then ravel can't handle the code correctly. It will treat the code as ARM and output garbage. Sadly, unlike otool, there is no force-Thumb mode in ravel so we can't do much.&lt;br /&gt;&lt;br /&gt;When nobody can save you, you have to save yourself. Therefore I've written a disassembler specially for Thumb mode. This disassembler can extract useful data and perform numerical arithmetic linearly (ignoring all branches). I term this &lt;strong&gt;Dumb Disassembler&lt;/strong&gt; as it doesn't perform branch analysis nor symbolic arithmetic. A &lt;strong&gt;Smart Disassembler&lt;/strong&gt; will do both and the result in decompiler-quality output.&lt;br /&gt;&lt;br /&gt;The Thumb Dumb Disassembler can be downloaded in &lt;a href="http://code.google.com/p/networkpx/downloads/detail?name=thumb-ddis.zip"&gt;thumb-ddis.zip&lt;/a&gt;. Unlike other networkpx projects, Thumb Dumb Disassembler is released in GPLv3. &lt;br /&gt;&lt;br /&gt;&lt;i&gt;(Sidetrack: What about the VFDecrypt key? In pre-3.0 &lt;a href="http://developer.apple.com/DOCUMENTATION/DARWIN/Reference/ManPages/man8/asr.8.html"&gt;asr&lt;/a&gt; there is a specific &lt;code&gt;__DATA,__restore&lt;/code&gt; section to store the key. In post-3.0 asr this is computed in run time using the SHA-1 and SHA-256 keys of the CPU identifier (s5l8900x) and the content of the &lt;strong&gt;whole&lt;/strong&gt; ramdisk. And then I got a 64-char incorrect password from it. There is another way to extract the key: run the asr, put a break point at 0x00011836, and retrieve the CFString at r0. On my device both the 2.2.1 and 3.0 asr Bus-errored me when I try to actually run them.)&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;hr /&gt;&lt;br /&gt;&lt;br /&gt;Now, let's talk about something not so technical. One of the new customer features in iPhoneOS 3.0 is the &lt;strong&gt;Spotlight&lt;/strong&gt;. But one essential component missing from the Mac OS X Spotlight is the &lt;strong&gt;&lt;a href="http://www.apple.com/macosx/features/300.html#spotlight"&gt;calculator&lt;/a&gt;&lt;/strong&gt;. &lt;br /&gt;&lt;br /&gt;When the SDK was just released, some developers noticed the directories &lt;code&gt;/System/Library/SearchBundles/*.searchBundle&lt;/code&gt; and it does mean Spotlight is extensible right? Indeed it is. &lt;br /&gt;&lt;br /&gt;After disassembling the 2 searchBundles in it, I have a rough idea of how these bundles work. So with minimum effort, I've created this &lt;code&gt;Calculator.searchBundle&lt;/code&gt;:&lt;br /&gt;&lt;img src="http://x08.xanga.com/e8ff36eb13633238198503/w188331118.jpg" /&gt;&lt;br /&gt;Because 3.0 is not jailbroken yet, only the Simulator version exists. If you have the SDK, you can now download &lt;a href="http://code.google.com/p/networkpx/downloads/detail?name=Calculator.searchBundle.zip"&gt;Calculator.searchBundle.zip&lt;/a&gt; to test the bundle. The source code is also provided (under BSD license) so you can code up your own.&lt;br /&gt;&lt;br /&gt;Note that the 3.0 SDK is not finalized so the code shown here may not work in June.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-5776863138478048302?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/5776863138478048302/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/03/releases-thumb-dumb-disassembler.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/5776863138478048302'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/5776863138478048302'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/03/releases-thumb-dumb-disassembler.html' title='Releases: Thumb Dumb Disassembler &amp; Calculator.searchBundle'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-3993468271777779017</id><published>2009-03-21T14:19:00.003+08:00</published><updated>2009-03-21T15:19:33.589+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='iKeyEx'/><title type='text'>3.0 Keyboard Changes</title><content type='html'>&lt;ul&gt;&lt;br /&gt;&lt;li&gt;The keyboard will now transit (by fading &amp; resizing) between landscape and portrait mode, i.e. the keyboard no longer hides when the orientation is changed (at least in Notes)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Emoji got landscape mode&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Accent view and popup view got less shadows -- I don't like this.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;When disabling an internal keyboard that was active, the OS no longer reset the whole keyboard list. This means fewer steps to replace internal keyboards by iKeyEx ones. ^_^&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;I've uploaded a &lt;a href="http://picasaweb.google.com/kennytm/IPhoneOS30Keyboards"&gt;gallery&lt;/a&gt; of the extra keyboards and interesting features in 3.0&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Some points worth noticing:&lt;/p&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Even though Arabic and Hebrew are RTL languages Apple doesn't bother to reverse the direction of the delete key. Probably &lt;i&gt;they&lt;/i&gt; think it is not very confusing.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;In Zhuyin, after you entered a consonant in the normal plane, it will automatically switch to the Shift plane for the vowels.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;In Greek, the final sigma is automatically detected, so you don't see a final sigma on the keyboard.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;I don't know if they're still using a standard keyboard (i.e. simple subclass of UIKeyboardLayoutRoman) for Thai and Zhuyin as the position of keys in normal plane and Shift plane are distinct. This cannot be done in 2.x at all.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Also I don't know if the accents view becoming multi-row is internal or not.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;Now excuse me trying to JB the 3.0 and extract the framework binaries...&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-3993468271777779017?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/3993468271777779017/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/03/30-keyboard-changes.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/3993468271777779017'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/3993468271777779017'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/03/30-keyboard-changes.html' title='3.0 Keyboard Changes'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-8788942838672284468</id><published>2009-03-18T23:56:00.002+08:00</published><updated>2009-03-18T23:59:10.330+08:00</updated><title type='text'>New Keyboards in 3.0:</title><content type='html'>Arabic,&lt;br /&gt;Hebrew,&lt;br /&gt;Malay,&lt;br /&gt;Thai,&lt;br /&gt;Chinese (Traditional) (Zhuyin 注音)&lt;br /&gt;&lt;br /&gt;Still no Chajei 倉頡 :(&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-8788942838672284468?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/8788942838672284468/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/03/new-keyboards-in-30.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/8788942838672284468'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/8788942838672284468'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/03/new-keyboards-in-30.html' title='New Keyboards in 3.0:'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-2957883308522856281</id><published>2009-03-18T03:17:00.001+08:00</published><updated>2009-03-18T03:19:24.150+08:00</updated><title type='text'>Nice job on Copy and Paste Apple,</title><content type='html'>But I hate shake to undo :p Nor does all the UIAlertViews for push notification.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-2957883308522856281?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/2957883308522856281/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/03/nice-job-on-copy-and-paste-apple.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/2957883308522856281'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/2957883308522856281'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/03/nice-job-on-copy-and-paste-apple.html' title='Nice job on Copy and Paste Apple,'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-5616796593899208836</id><published>2009-03-17T17:33:00.008+08:00</published><updated>2009-03-17T22:53:14.301+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='5RowQWERTY'/><category scheme='http://www.blogger.com/atom/ns#' term='iKeyEx'/><title type='text'>iKeyEx &amp; 5-Row QWERTY 0.1-9b (Beta) Released</title><content type='html'>First of all, about the versioning schemes -- From now on all beta versions (those I put in the project download page and my private beta Repo) will have an odd revision, and the public versions will have an even revision (those you see in BigBoss). Therefore, the following beta versions will be called 0.1-9c, -9d, etc., and the release version will be 0.1-10.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;iKeyEx&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;So back to iKeyEx. What's new in 0.1-9b has actually been highlighted in the last post. I'll go to the detail and implementation of each feature now.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;More than 10 variants&lt;/h3&gt;&lt;br /&gt;Prior to 0.1-9b the number of variants supported must be less than 10 because if there's more the buttons will leak off the screen and become useless. In 0.1-9b the system will automatically reduce the size of each button to try to allow more keys to be shown.&lt;br /&gt;&lt;br /&gt;&lt;img src="http://2.bp.blogspot.com/_7Ek7e48Yovg/Sb-wlaLr_MI/AAAAAAAAAD0/eRRIhDgOsJY/s320/Untitled+2.jpg" /&gt;&lt;br /&gt;&lt;br /&gt;The upper limit is now pushed to 12. Larger than 12 the variants list will start to act weirdly. &lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Variants Labeling&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;Following layout.plist, the variants can also be "labeled", i.e. the text shown on the button can be different from what will actually be typed. This is done by declaring an array instead of a string, e.g.&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;M = (M, ("Dear all,\n\n\n\nBest Regards,\nMe", Mail))&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;will create a Mail button on the list of variants, and when selected, will generate the "Dear all, ..." text.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Splitting of Landscape and Portrait Mode&lt;/h3&gt;&lt;br /&gt;The type of UIKeyboardLayoutCLass key has been generalized. As a result, not only code can have separate layouts in landscape and portrait mode, the other two methods (layout.plist and referred) can be split too. &lt;br /&gt;&lt;br /&gt;The syntax is simple:&lt;br /&gt;&lt;blockquote&gt;&lt;pre&gt;UIKeyboardLayoutClass = {&lt;br /&gt;  Portrait = "abc.plist";&lt;br /&gt;  Landscape = "xyz.plist";&lt;br /&gt;};&lt;/pre&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Keyboard Mode Jumping&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;An extra feature in iKeyEx -- you can now hold down the International button (the Globe) for more than 1 second, then release it to get a list of keyboards enabled. &lt;br /&gt;&lt;img src="http://4.bp.blogspot.com/_7Ek7e48Yovg/Sb-zS4onRaI/AAAAAAAAAD8/oqY1KsLaD30/s320/Untitled.png" /&gt;&lt;br /&gt;Click on an item to go directly to that keyboard.&lt;br /&gt;&lt;blockquote&gt;&lt;b&gt;Note:&lt;/b&gt; This feature is not available in the Emoji keyboard. 3rd-party IMEs not based on iKeyEx cannot be identified.&lt;/blockquote&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;b&gt;Note:&lt;/b&gt; In 0.1-9c you don't even need to release the button -- just keep pressing it and the keyboard list will show automatically. But in 0.1-9b you still need to lift your finger.&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Email Diagnosis Info&lt;/h3&gt;&lt;br /&gt;&lt;img src="http://4.bp.blogspot.com/_7Ek7e48Yovg/Sb-0v_vHcoI/AAAAAAAAAEE/ppbvepWJZdY/s320/Untitled.png" /&gt; &lt;img src="http://3.bp.blogspot.com/_7Ek7e48Yovg/Sb-1HQh8cvI/AAAAAAAAAEM/RCt9qVhqNlY/s320/Untitled.jpg" /&gt; &lt;img src="http://3.bp.blogspot.com/_7Ek7e48Yovg/Sb-2B-U-MjI/AAAAAAAAAEU/RCEWyTE1RTk/s320/Untitled.jpg" /&gt;&lt;br /&gt;&lt;br /&gt;The last, and the most important feature in this upgrade is the Email Diagnosis Info button in Settings -&gt; iKeyEx -&gt; Troubleshooting. I've got lots of crash reports but the SSH process is pretty troublesome for most users. Therefore I've created this button to simplify the process.  The files attached are:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Recent crashes related to iKeyEx (i.e. /User/Library/Logs/CrashReporter/*.plist which have the substring "iKeyEx.dylib␣␣" in the file)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;The list of installed Cydia packages (i.e. dpkg -l)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;syslog (/var/log/syslog)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;.GlobalPreferences.plist for the list of enabled keyboards (/User/Library/Preferences/.GlobalPreferences.plist)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;com.apple.Preferences.plist for the active keyboard (/User/Library/Preferences/com.apple.Preferences.plist)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;The content of /User/Library/Keyboard/ and /Library/iKeyEx/Keyboards/&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;This also serves as a demonstration on how to send email without leaving the application, and how to attach files and data to the message. &lt;br /&gt;&lt;br /&gt;&lt;h3&gt;etc.&lt;/h3&gt;&lt;br /&gt;There are some minor tweaks in this version, including:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;The /Library/iKeyEx/ folder is now a symlink to /var/stash/iKeyEx.XXXXXX/ to free up precious space in the / partition.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;An "InputManagers" folder is created besides "Keyboards" folder. Eventually in 0.2 the input managers will be split from keyboard layouts and allowed to mashed up, but now this is just an empty placeholder.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;All keyboards with name starting with __ are reserved for internal use now.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;5-Row QWERTY Keyboard&lt;/h2&gt;&lt;br /&gt;5-Row QWERTY is also updated, but it is basically a bug-fix update. The &lt;a href="http://code.google.com/p/networkpx/wiki/ChangeLog#0.1-10"&gt;ChangeLog&lt;/a&gt; has already summarized the changes.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-5616796593899208836?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/5616796593899208836/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/03/ikeyex-5-row-qwerty-01-9b-beta-released.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/5616796593899208836'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/5616796593899208836'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/03/ikeyex-5-row-qwerty-01-9b-beta-released.html' title='iKeyEx &amp; 5-Row QWERTY 0.1-9b (Beta) Released'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_7Ek7e48Yovg/Sb-wlaLr_MI/AAAAAAAAAD0/eRRIhDgOsJY/s72-c/Untitled+2.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-8315441952840979041</id><published>2009-03-14T03:34:00.003+08:00</published><updated>2009-03-14T04:00:28.191+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='iKeyEx'/><title type='text'>One week of inactivity?</title><content type='html'>The networkpx project was inactive for the whole week. Why? If you see the last post you should know I was trying to implement a screen video capturer. Eventually it's a miserable failure. The problem is lack of RAM -- the capturing program uses too many resources and caused a &lt;i&gt;kernel panic&lt;/i&gt;. So I have eventually got rid of the idea. Instead, a viable solution would be capturing through the USB cable with the MobileDevice (private) framework. I don't know MobileDevice, so let's put it aside. &lt;br /&gt;&lt;br /&gt;So what now? I'm upgrading iKeyEx to the next minor version 0.1-10. Features included or expected to include are:&lt;ul&gt;&lt;li&gt;Squeezing the variants when there's more than 10 of them, so Vietnamese accents can be shown properly (implemented)&lt;/li&gt;&lt;li&gt;Allow disassociating portrait and landscape mode in layout.plist&lt;/li&gt;&lt;li&gt;"Email diagnosis info", which automatically sends all the crash log to me by mail. I create this because many issue reporters failed to give me the info I really needed :( so let's automate it.&lt;/li&gt;&lt;li&gt;Long press the globe to select a keyboard to jump to. &lt;/li&gt;&lt;li&gt;Labels for variants. &lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;This will not be the last version of the 0.1 line because there are still numerous crash reports floating around. The "Email diagnosis info" will be the key feature that allows more accurate crash data collection. Then hopefully 0.1-11 will be the last of 0.1-*. &lt;br /&gt;&lt;br /&gt;(if you're a (non-SDK) developer and wants to implement similar feature, you can look into src/MailCrashLog.m and src/UIKit3/UIMailComposeView.m of the SVN trunk now.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-8315441952840979041?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/8315441952840979041/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/03/one-week-of-inactivity.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/8315441952840979041'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/8315441952840979041'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/03/one-week-of-inactivity.html' title='One week of inactivity?'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-3690039736201693833</id><published>2009-03-10T02:15:00.003+08:00</published><updated>2009-03-10T02:20:22.208+08:00</updated><title type='text'>iPhone Screen Video Capturing</title><content type='html'>&lt;object width="320" height="266" class="BLOG_video_class" id="BLOG_video-20313369af8b2561" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"&gt;&lt;param name="movie" value="http://www.youtube.com/get_player"&gt;&lt;param name="bgcolor" value="#FFFFFF"&gt;&lt;param name="allowfullscreen" value="true"&gt;&lt;param name="flashvars" value="flvurl=http://v10.nonxt4.googlevideo.com/videoplayback?id%3D20313369af8b2561%26itag%3D5%26app%3Dblogger%26ip%3D0.0.0.0%26ipbits%3D0%26expire%3D1329873234%26sparams%3Did,itag,ip,ipbits,expire%26signature%3D6582D10F7B223E0846C78A8AE272082BAC611C89.34FA401DBD3882DA99C6A752599BD42C72E0D8D4%26key%3Dck1&amp;amp;iurl=http://video.google.com/ThumbnailServer2?app%3Dblogger%26contentid%3D20313369af8b2561%26offsetms%3D5000%26itag%3Dw160%26sigh%3DYdmTBW5-N8gM0li9bmQ1-MVCz5w&amp;amp;autoplay=0&amp;amp;ps=blogger"&gt;&lt;embed src="http://www.youtube.com/get_player" type="application/x-shockwave-flash"width="320" height="266" bgcolor="#FFFFFF"flashvars="flvurl=http://v10.nonxt4.googlevideo.com/videoplayback?id%3D20313369af8b2561%26itag%3D5%26app%3Dblogger%26ip%3D0.0.0.0%26ipbits%3D0%26expire%3D1329873234%26sparams%3Did,itag,ip,ipbits,expire%26signature%3D6582D10F7B223E0846C78A8AE272082BAC611C89.34FA401DBD3882DA99C6A752599BD42C72E0D8D4%26key%3Dck1&amp;iurl=http://video.google.com/ThumbnailServer2?app%3Dblogger%26contentid%3D20313369af8b2561%26offsetms%3D5000%26itag%3Dw160%26sigh%3DYdmTBW5-N8gM0li9bmQ1-MVCz5w&amp;autoplay=0&amp;ps=blogger"allowFullScreen="true" /&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;(Yes, I know the colors are all wrong, and the time sequence is strange, but these are very easy to fix.)&lt;/p&gt;&lt;br /&gt;&lt;p&gt;(The video is blurred solely because of conversion.)&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-3690039736201693833?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='enclosure' type='video/mp4' href='http://www.blogger.com/video-play.mp4?contentId=20313369af8b2561&amp;type=video%2Fmp4' length='0'/><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/3690039736201693833/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/03/iphone-screen-video-capturing.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/3690039736201693833'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/3690039736201693833'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/03/iphone-screen-video-capturing.html' title='iPhone Screen Video Capturing'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-4358634654154360766</id><published>2009-03-07T00:49:00.004+08:00</published><updated>2009-03-08T01:29:51.726+08:00</updated><title type='text'>To move folders in / to /var/stash/</title><content type='html'>Add this line to preinst:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;if [[ $1 == install ]]; then&lt;br /&gt;  /usr/libexec/cydia/move.sh &amp;lt;FULLPATH-YOU-WANT-TO-MOVE-FROM&amp;gt;&lt;br /&gt;  ...&lt;br /&gt;fi;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;But it seems no way to clean it up.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-4358634654154360766?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/4358634654154360766/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/03/to-move-folders-in-to-varstash.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/4358634654154360766'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/4358634654154360766'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/03/to-move-folders-in-to-varstash.html' title='To move folders in / to /var/stash/'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-3399779547672280682</id><published>2009-03-03T21:49:00.002+08:00</published><updated>2009-03-03T22:31:14.319+08:00</updated><title type='text'>Arbitrary HTML in Google Code wiki</title><content type='html'>Google Code supports a limited subset of HTML in Wiki. In particular, &amp;lt;input/&amp;gt; cannot be used. Because of this, the early version of &lt;a href="http://code.google.com/p/networkpx/wiki/CopyingTextFromSafari"&gt;CopyingTextFromSafari&lt;/a&gt; uses the traditional "go to a link and bookmark it" mechanism to add the bookmarklet.&lt;br /&gt;&lt;br /&gt;Then today I realized that I could use HTML in Google Gadgets. So I can just&lt;ul&gt;&lt;li&gt;Put all HTML in an XML file and upload the file to SVN.&lt;/li&gt;&lt;li&gt;Insert a &amp;lt;wiki:gadget/&amp;gt; with URL to the wiki page.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;I've immediately changed CopyingTextFromSafari, and also added a Donate button to the front page after figuring this out.&lt;br /&gt;&lt;br /&gt;One slight note is that the HTML you use will live inside an iframe.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-3399779547672280682?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/3399779547672280682/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/03/arbitrary-html-in-google-code-wiki.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/3399779547672280682'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/3399779547672280682'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/03/arbitrary-html-in-google-code-wiki.html' title='Arbitrary HTML in Google Code wiki'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-4867330367405287033</id><published>2009-03-03T16:20:00.004+08:00</published><updated>2009-03-03T16:36:12.652+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='5RowQWERTY'/><category scheme='http://www.blogger.com/atom/ns#' term='iKeyEx'/><title type='text'>0.1-8</title><content type='html'>I've sent iKeyEx and 5-Row QWERTY (which isn't 5-Row nor QWERTY anymore :p) 0.1-8 to BigBoss. Yes this time is real.&lt;br /&gt;&lt;br /&gt;iKeyEx 0.1-8 fixes a critical crash on pre-2.2 firmwares. Users of pre-2.2 users should upgrade to iKeyEx 0.1-8 (or just upgrade to firmware 2.2.1!). Hopefully all crashes will be solved soon so that I can end the 0.1-* chronology.&lt;br /&gt;&lt;br /&gt;5-Row QWERTY 0.1-8 adds a lot of customizations. Pretty much of these have been covered on &lt;a href="http://www.iclarified.com/entry/index.php?enid=3090"&gt;iClarified&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-4867330367405287033?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/4867330367405287033/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/03/01-8.html#comment-form' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/4867330367405287033'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/4867330367405287033'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/03/01-8.html' title='0.1-8'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-2565149257412038014</id><published>2009-03-01T20:34:00.005+08:00</published><updated>2009-03-01T21:07:12.854+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='iKeyEx'/><title type='text'>Issue 67</title><content type='html'>iKeyEx 0.1-6 crashes some machines. This is a known problem, a very critical problem, but I did not know how to reproduce it. Fortunately, a proper bug report finally appear as &lt;a href="http://code.google.com/p/networkpx/issues/detail?id=67"&gt;issue 67&lt;/a&gt; and I got to know what has happened. Turns out it's a firmware issue. In ≥2.2 there is a message named&lt;br /&gt;&lt;br /&gt;-[UIKeyboardSublayout setIsShiftKeyPlaneChooser:]&lt;br /&gt;&lt;br /&gt;which does not present on ≤2.1. In Objective-C, any unrecognized messages will cause an exception to be raised. Since I did not setup any exception handlers, the result is obvious -- crash.&lt;br /&gt;&lt;br /&gt;There is another piece of message that is new in 2.2:&lt;br /&gt;&lt;br /&gt;+[UIHardware _playSystemSound:]&lt;br /&gt;&lt;br /&gt;These 2 should make hClipboard and iKeyEx-derived keyboards unusable in ≤2.1.&lt;br /&gt;&lt;br /&gt;I should have caught these when I claimed &lt;a href="http://code.google.com/p/networkpx/issues/detail?id=7"&gt;issue 7&lt;/a&gt; is solved. But why not? This is pretty much an issue of how Objective-C work.&lt;br /&gt;&lt;br /&gt;Issue 7 was filed because I found that the linker for 2.0 and 2.1 emitted errors. All external C and C++ functions must be processed by the linker, and if something is missing (even if the header file said it was there), we can immediately know. But Objective-C is different. Objective-C dispatches message implementation dynamically. That's why Category and method swizzling works. But this flexibility means no compile-time check can be done. And the runtime check causes crashes. &lt;br /&gt;&lt;br /&gt;What I've done immediately after recognizing the root cause of issue 67 is to build the &lt;a href="http://code.google.com/p/networkpx/wiki/API_Diffs"&gt;API diff table&lt;/a&gt;. This allows developers to easily see what's new and what's missing during firmware transition, and determine whether a respondsToSelector: call is worth it. &lt;br /&gt;&lt;br /&gt;Meanwhile, iKeyEx v0.1-8 fixing the 2 calls has been uploaded to Google code as well.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-2565149257412038014?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/2565149257412038014/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/03/issue-67.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/2565149257412038014'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/2565149257412038014'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/03/issue-67.html' title='Issue 67'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-2150277453576802957</id><published>2009-03-01T18:42:00.006+08:00</published><updated>2009-03-01T19:43:15.569+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='hClipboard'/><title type='text'>&lt;Post deprecated&gt;</title><content type='html'>The problem is fixed. Install hClipboard as you wish :)&lt;br /&gt;&lt;br /&gt;&lt;del&gt;The "latest" version of hClipboard seems to be mispackaged. While it is shown as 0.1-5, the content is actually 0.0-1, the initial buggy version.&lt;br /&gt;&lt;br /&gt;I don't know what happened. I haven't sent any new packages to any repositories after Feb 19th.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Please do not "upgrade" to this version, because you are in fact downgrading&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;If you have unfortunately "upgraded", you can remove that package, then install 0.1-5 from &lt;a href="http://code.google.com/p/networkpx/downloads/detail?name=hk.kennytm.hClipboard-0.1-5.deb"&gt;http://code.google.com/p/networkpx/downloads/detail?name=hk.kennytm.hClipboard-0.1-5.deb&lt;/a&gt;.&lt;/del&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-2150277453576802957?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/2150277453576802957/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/03/do-not-upgrade-to-latest-version-of.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/2150277453576802957'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/2150277453576802957'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/03/do-not-upgrade-to-latest-version-of.html' title='&amp;lt;Post deprecated&amp;gt;'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-2517212791338671969</id><published>2009-02-27T18:54:00.005+08:00</published><updated>2009-02-27T19:39:57.953+08:00</updated><title type='text'>0x51EB851F wha?</title><content type='html'>I am decompiling KBWordSearch for .cin support, but I encountered a strange piece of ASM:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt; +00174 30b9536c 34329FE5 loc_000174: ldr               r3,[pc,#0x234]&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt; +00178 30b95370 C7208BE2             add               r2,fp,#0xc7&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt; +0017c 30b95374 9302C1E0             smull             r0,r1,r3,r2&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt; +00180 30b95378 C23FA0E1             mov               r3,r2,asr #31&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt; +00184 30b9537c 41B363E0             rsb               fp,r3,r1,asr #6&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt; +00188 30b95380 30109DE5&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt; +0018c 30b95384 8B32A0E1             mov               r3,fp,lsl #5&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt; +00190 30b95388 8B3183E0             add               r3,r3,fp,lsl #3&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt; +00194 30b9538c 033183E0             add               r3,r3,r3,lsl #2&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt; +00198 30b95390 02B063E0             rsb               fp,r3,r2&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;which translates to:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;// in: index&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;// out: next_index&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;capacity = 200;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;r2 = index + capacity - 1;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;r1 = r2 * 0x51EB851F;    // take upper dword only.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;fp = (r1 &gt;&gt; 6) - (r2 &gt;&gt; 31);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;next_index = r2 - fp*160;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;(0x51EB851F is the lower dword of 3.14 in IEEE double, and also 2&lt;sup&gt;37&lt;/sup&gt;/100+1) Can someone explain what this code is doing?&lt;br /&gt;&lt;br /&gt;Edit: Turns out to be a division. Ref: &lt;a href="http://d.hatena.ne.jp/h0shu/20080302/p2"&gt;http://d.hatena.ne.jp/h0shu/20080302/p2&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;r2 = index + capacity - 1;&lt;br /&gt;next_index = r2 - (r2/capacity)*160;&lt;br /&gt;&lt;br /&gt;Why are they doing things like this is beyond me.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-2517212791338671969?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/2517212791338671969/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/02/0x51eb851f-wha.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/2517212791338671969'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/2517212791338671969'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/02/0x51eb851f-wha.html' title='0x51EB851F wha?'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-5145794537734106713</id><published>2009-02-27T00:59:00.007+08:00</published><updated>2009-02-27T01:35:28.993+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='5RowQWERTY'/><category scheme='http://www.blogger.com/atom/ns#' term='iKeyEx'/><title type='text'>iKeyEx &amp; 5-Row QWERTY 0.1-7 Released</title><content type='html'>I was not updating last few days because I wanna clear all the homework first. Anyway, there's no major update about ⌘, but there is a huge addition in 5-Row QWERTY.&lt;br /&gt;&lt;br /&gt;The front end to modify Info.plist &amp;amp; layout.plist of 5-Row QWERTY has been implemented in v0.1-7, so that you can:&lt;br /&gt;&lt;ul&gt;&lt;li&gt; Change the auto-correction language, or even use the built-in IMEs:&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_7Ek7e48Yovg/SabO4_F_9QI/AAAAAAAAADU/oezrEFgfmNs/s1600-h/Untitled.jpg"&gt;&lt;br /&gt;&lt;img style="cursor: pointer; width: 214px; height: 320px;" src="http://3.bp.blogspot.com/_7Ek7e48Yovg/SabO4_F_9QI/AAAAAAAAADU/oezrEFgfmNs/s320/Untitled.jpg" alt="" id="BLOGGER_PHOTO_ID_5307156689307301122" border="0" /&gt;&lt;/a&gt; (5-Row QWERTY × Traditional Chinese Pinyin IME)&lt;/li&gt;&lt;li&gt;Change the default layout to QWERTZ, QZERTY, AZERTY and many others&lt;/li&gt;&lt;li&gt;Totally customize the special characters, e.g. change the ^ to ?, $ to €, etc.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_7Ek7e48Yovg/SabQ5aqaR0I/AAAAAAAAADk/3w7K01Ey6d8/s1600-h/Untitled.jpg"&gt;&lt;img style="cursor: pointer; width: 214px; height: 320px;" src="http://4.bp.blogspot.com/_7Ek7e48Yovg/SabQ5aqaR0I/AAAAAAAAADk/3w7K01Ey6d8/s320/Untitled.jpg" alt="" id="BLOGGER_PHOTO_ID_5307158895731033922" border="0" /&gt;&lt;/a&gt; &lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_7Ek7e48Yovg/SabRBy2YO0I/AAAAAAAAADs/qg4F3mKpDpU/s1600-h/Untitled2.jpg"&gt;&lt;img style="cursor: pointer; width: 214px; height: 320px;" src="http://4.bp.blogspot.com/_7Ek7e48Yovg/SabRBy2YO0I/AAAAAAAAADs/qg4F3mKpDpU/s320/Untitled2.jpg" alt="" id="BLOGGER_PHOTO_ID_5307159039662635842" border="0" /&gt;&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;There are a few bug fixes and improvements as well, which are recorded in the &lt;a href="http://code.google.com/p/networkpx/wiki/ChangeLog"&gt;ChangeLog&lt;/a&gt; as usual.&lt;br /&gt;&lt;br /&gt;iKeyEx 0.1-7 is a minor update which addresses a few bugs. However, the &lt;a href="http://code.google.com/p/networkpx/issues/detail?id=62"&gt;critical one&lt;/a&gt; still has not been fixed because no one has ever given me a crash log or a useful crash log.&lt;br /&gt;&lt;br /&gt;Although the layout engine of 5-Row QWERTY only depends on 0.1-6, the preferences binary depends on a single 0.1-7 function "iKeyEx_KBMan" for clearing the cache quickly. Therefore you still need to upgrade iKeyEx to make it work.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-5145794537734106713?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/5145794537734106713/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/02/ikeyex-5-row-qwerty-01-7-released.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/5145794537734106713'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/5145794537734106713'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/02/ikeyex-5-row-qwerty-01-7-released.html' title='iKeyEx &amp; 5-Row QWERTY 0.1-7 Released'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_7Ek7e48Yovg/SabO4_F_9QI/AAAAAAAAADU/oezrEFgfmNs/s72-c/Untitled.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-3849744661961415316</id><published>2009-02-22T02:54:00.002+08:00</published><updated>2009-02-22T02:57:27.327+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Command'/><title type='text'>⌘ Development Progress Day 3</title><content type='html'>Nothing technical, so let's see some screenshots:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_7Ek7e48Yovg/SaBONKeEQ_I/AAAAAAAAADE/1kvj6FWzXnk/s1600-h/Command1.jpg"&gt;&lt;img style="cursor: pointer; width: 166px; height: 320px;" src="http://3.bp.blogspot.com/_7Ek7e48Yovg/SaBONKeEQ_I/AAAAAAAAADE/1kvj6FWzXnk/s320/Command1.jpg" alt="" id="BLOGGER_PHOTO_ID_5305326349098173426" border="0" /&gt;&lt;/a&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_7Ek7e48Yovg/SaBOdOXo-gI/AAAAAAAAADM/9bNzLR3WN4Q/s1600-h/Command2.jpg"&gt;&lt;img style="cursor: pointer; width: 320px; height: 166px;" src="http://3.bp.blogspot.com/_7Ek7e48Yovg/SaBOdOXo-gI/AAAAAAAAADM/9bNzLR3WN4Q/s320/Command2.jpg" alt="" id="BLOGGER_PHOTO_ID_5305326625022867970" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-3849744661961415316?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/3849744661961415316/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/02/development-progress-day-3.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/3849744661961415316'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/3849744661961415316'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/02/development-progress-day-3.html' title='⌘ Development Progress Day 3'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_7Ek7e48Yovg/SaBONKeEQ_I/AAAAAAAAADE/1kvj6FWzXnk/s72-c/Command1.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-3655895392526759859</id><published>2009-02-21T13:57:00.000+08:00</published><updated>2009-02-21T13:58:52.389+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='fun'/><title type='text'>Spelling error slipped into production</title><content type='html'>Open UIKit (2.2), and search for UI&lt;span style="font-style:italic;"&gt;Resrouce&lt;/span&gt;BundleForNIBBeingDecodedWithCoder. Lol.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-3655895392526759859?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/3655895392526759859/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/02/spelling-error-slipped-into-production.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/3655895392526759859'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/3655895392526759859'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/02/spelling-error-slipped-into-production.html' title='Spelling error slipped into production'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-6953851333182881794</id><published>2009-02-20T19:00:00.003+08:00</published><updated>2009-02-20T23:19:18.477+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Command'/><title type='text'>⌘ Development Progress Day 2</title><content type='html'>Now that UILabel is all set, I continue to hook other texts that are long enough to be "commanded", e.g. the UITableHeaderFooterView. There are also some reluctant UILabel that refuses to be hooked. For these I hooked their superviews (UINavigationBar &amp;amp; UIPickerTable) for extracting the text info.&lt;br /&gt;&lt;br /&gt;And here comes the real challenge: hooking the UIWebDocumentView. Yes I knew the Clippy 0.95-5 experiment was failed. But this does not prevent anyone else from finding another way to achieve the same goal right?&lt;br /&gt;&lt;br /&gt;My first naïve approach is to get the DOM node at the touch point, like this:&lt;br /&gt;&lt;br /&gt;[[self webView] elementAtPoint:(touchPoint)];&lt;br /&gt;&lt;br /&gt;and like Clippy 0.95-5, it crashes immediately at the 2nd touch. If I trace the class of the returned object*, I can see the class changes from e.g. DOMHTMLAnchorElement to NSCFType. In fact I encountered this before once when trying to implement setSelection() to &amp;lt;textarea/&amp;gt; and &amp;lt;input/&amp;gt; in ℏClipboard using the DOMRange object. &lt;span style="font-style: italic;"&gt;It fails on the 2nd call&lt;/span&gt;. I call this the "&lt;a href="http://en.wikipedia.org/wiki/Uncertainty_principle#Uncertainty_principle_and_observer_effect"&gt;observer effect&lt;/a&gt;". Right after you "observed" any DOM objects, the object will "collapse" and you can't reference it reliably anymore.&lt;br /&gt;&lt;br /&gt;A workaround is to -retain it right after the DOM object is accessed. But this introduces memory leak. This is really a last-resort option.&lt;br /&gt;&lt;br /&gt;And actually it turns out to be work done too complicated. There is a -[UIWebDocumentView approximateNodeAtViewportLocation:] method in the Interaction category which can easily be overlooked. It returns a DOMNode &lt;span style="font-style: italic;"&gt;without&lt;/span&gt; any observer effect AFAIK. Except it crashes on 2.2 complaining ASSERTION FAILED: !WebThreadIsEnabled() || WebThreadIsLocked(). Well that's easy enough to solve. Just lock the WebThread() everytime we need to access this method.&lt;br /&gt;&lt;br /&gt;So I used:&lt;br /&gt;&lt;br /&gt;WebThreadLock();&lt;br /&gt;DOMNode* activeNode = [self &lt;span style="font-weight: bold;"&gt;approximateNodeAtViewportLocation&lt;/span&gt;:&amp;amp;(touchPoint)];&lt;br /&gt;WebThreadUnlock();&lt;br /&gt;&lt;br /&gt;and done! The DOMNode is got and we can do anything we want. Too good to be true. Turns out the DOMNode will only be returned on any objects that have actions, i.e., &amp;lt;a&amp;gt;, &amp;lt;input/&amp;gt;, &amp;lt;textarea/&amp;gt;, &amp;lt;img/&amp;gt;, any thing that has onXXX events, &lt;span style="font-style: italic;"&gt;but not static texts&lt;/span&gt;. If touchPoint is on a static text, nil will be returned.&lt;br /&gt;&lt;br /&gt;But why this method prevents the observer effect? After lots of experiments, finally it turns out that it's the WebThreadLock() and WebThreadUnlock() doing the tricks. In fact, if I do&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;WebThreadLock();&lt;/span&gt;&lt;br /&gt;[[self webView] elementAtPoint:(touchPoint)];&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;WebThreadUnlock();&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;then everything works perfectly! At least in the simulator. (Hey Ryan, if you're reading this, as now I've solved this problem, can you add Safari copying back in Clippy 0.95-6? :D)&lt;br /&gt;&lt;br /&gt;So, at the end of Day 2, I can hook to any DOMNodes, besides UILabel, UITableHeaderFooterView, UINavigationBar and UIPickerTable.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Note: -[WebView elementAtPoint:] returns a subclass of NSDictionary. By the returned object I mean the value corresponding to the WebElementDOMNode key.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-6953851333182881794?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/6953851333182881794/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/02/development-progress-day-2.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/6953851333182881794'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/6953851333182881794'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/02/development-progress-day-2.html' title='⌘ Development Progress Day 2'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-7381324479185695089</id><published>2009-02-19T23:19:00.004+08:00</published><updated>2009-02-19T23:54:41.777+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Command'/><title type='text'>⌘ Development Progress Day 1</title><content type='html'>OK, now iKeyEx 0.1-6 has been released, let's turn into the other project left over: ⌘.&lt;br /&gt;&lt;br /&gt;⌘ was proposed on Jan 26th as a solution to &lt;a href="http://code.google.com/p/networkpx/issues/detail?id=10"&gt;issue 10&lt;/a&gt;. You can read the design concept &lt;a href="http://code.google.com/p/networkpx/wiki/CommandDesignConcept"&gt;here&lt;/a&gt;. As I develop the app, I'll keep updating the progress on this blog.&lt;br /&gt;&lt;br /&gt;The first thing I've done is to intercept touches coming to a UILabel using -[UILabel touchesBegan:withEvent:]. It turns out not so easy. By default UILabel ignores all touches. But setting userInteractionEnabled = YES does not solve the problem at all (at least in 2.0 firmware). As usual, when something does not work, I look into the UIKit's assembly code. And it turns out that there is a -[UILabel ignoresMouseEvents] method. So I quickly hooked it to always return NO. Then the test application crashed, complaining -[UIScrollView old_touchesBegan:withEvent:] not found. But hey, I did not do anything to the UIScrollView! What's wrong? Turns out the implementation of -[UIResponder touchesBegan:withEvent:] looks like this:&lt;br /&gt;&lt;br /&gt;-(void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {&lt;br /&gt;   &lt;span style="font-weight: bold;"&gt;forwardMethod2&lt;/span&gt;(self, _cmd, touches, event);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;where forwardMethod2() is equivalently the statement [[self nextResponder] performSelector:_cmd withObject:touches withObject:event]. This pattern is used for all touchesXXX:withEvent: messages. Now since I have renamed the old touchesBegan:withEvent: for UILabel only, and my code forwards the message to the next responder (the UIScrollView), and it does not recognize old_touchesBegan:withEvent: -- blam, crash.&lt;br /&gt;&lt;br /&gt;As a result, I have to store the old IMP before MobileSubstrate-ing it, and invoke the old message like this:&lt;br /&gt;&lt;br /&gt;-(void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {&lt;br /&gt;  NSLog(@"&gt;&gt;&gt; %@", self.text);&lt;br /&gt;  &lt;span style="font-weight: bold;"&gt;old_touchesBegan_withEvent&lt;/span&gt;(self, _cmd, touches, event);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;With this, I can hook all UILabels in the simulator.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-7381324479185695089?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/7381324479185695089/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/02/development-progress-day-1.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/7381324479185695089'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/7381324479185695089'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/02/development-progress-day-1.html' title='⌘ Development Progress Day 1'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-4639140443109035822</id><published>2009-02-19T08:07:00.002+08:00</published><updated>2009-02-19T08:10:05.095+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='5RowQWERTY'/><category scheme='http://www.blogger.com/atom/ns#' term='iKeyEx'/><category scheme='http://www.blogger.com/atom/ns#' term='hClipboard'/><title type='text'>Upgrades</title><content type='html'>I've sent the latest versions (r167) of iKeyEx, ℏClipboard, 5 Row QWERTY, L33tTyper and MathTyper to the BigBoss. Hopefully they'll be available tonight.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-4639140443109035822?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/4639140443109035822/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/02/upgrades.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/4639140443109035822'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/4639140443109035822'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/02/upgrades.html' title='Upgrades'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3540073447780295551.post-7912870337861272228</id><published>2009-02-18T11:33:00.004+08:00</published><updated>2009-02-19T08:07:11.612+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='5RowQWERTY'/><category scheme='http://www.blogger.com/atom/ns#' term='iKeyEx'/><category scheme='http://www.blogger.com/atom/ns#' term='hClipboard'/><title type='text'>5 Row QWERTY 0.1-6 released</title><content type='html'>5 Row QWERTY 0.1-6 is released, and iKeyEx is also upgraded to 0.1-6 to support the features of it.&lt;br /&gt;&lt;br /&gt;I've put up a few cached images of the new layout at &lt;a href="http://code.google.com/p/networkpx/wiki/Using_5RowQWERTY"&gt;http://code.google.com/p/networkpx/wiki/Using_5RowQWERTY&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;BTW, if there's no more blocking issues, the new versions of iKeyEx, ℏClipboard, 5 Row QWERTY, MathTyper and L33tTyper should hit BigBoss tomorrow morning (GMT+8).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3540073447780295551-7912870337861272228?l=networkpx.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://networkpx.blogspot.com/feeds/7912870337861272228/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://networkpx.blogspot.com/2009/02/5-row-qwerty-01-6-released.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/7912870337861272228'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3540073447780295551/posts/default/7912870337861272228'/><link rel='alternate' type='text/html' href='http://networkpx.blogspot.com/2009/02/5-row-qwerty-01-6-released.html' title='5 Row QWERTY 0.1-6 released'/><author><name>KennyTM~</name><uri>http://www.blogger.com/profile/13952454490450371593</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
