Okay, back for more!
Quote:
Originally Posted by Doitsu
If you haven't already done so, check the ePub source file with epubcheck online.
Also try to sideload the hybrid .mobi file that Kindle Previewer creates to find out if the mobi7 file has problems, too.
|
Good suggestions. From EPUB-Checker, the OSX wrapper for epubcheck:
Quote:
Validating against EPUB version 2.0
(http://code.google.com/p/epubcheck/)
May 12, 2015 10:41:23 AM PDT
---------------------------------------------------
No errors or warnings detected
|
I also sideloaded the hybrid .mobi from Kindlegen, and it reads fine on K4iOS. It has some formatting issues compared to reading it on an eInk Kindle, but no errors or anything.
Quote:
Originally Posted by DaleDe
I think that you may have to just pull some of those files into a text editor and look at them. That is what I did to decode the AZK in the first place and then poked around a bit. The file command in Unix can sometimes magic a value. The AZK I took apart was one assembled as part of the previewer. It is likely that Amazon would massage that file before shipping it as a real file. In the very least they would remove the redundancy of file data in source formats. I suspect it was a single file download that was unpacked for use and there may have been some massaging but whether at the source or on the unit is anybody's guess.
|
The book.kcr is a sqlite3 database. Hitting it with the sqlite command-line tool and executing the ".schema" command produces this (I omitted the indexes and built-in tables):
Code:
sqlite> .schema
CREATE TABLE ZBOOKPIECE ( Z_PK INTEGER PRIMARY KEY, Z_ENT INTEGER, Z_OPT INTEGER, ZPIECEID INTEGER, ZTYPE INTEGER, ZENCRYPTEDJSON BLOB );
CREATE TABLE ZLOCATIONMAP ( Z_PK INTEGER PRIMARY KEY, Z_ENT INTEGER, Z_OPT INTEGER, ZLOCATION INTEGER, ZPOSITION INTEGER );
In my case, book.kcr is about 8MB, although my book is quite large. The files in the "resources" folder are anywhere from 150KB to 80B. So it looks like the book itself is stored in the ZBOOKPIECE, in the ZENCRYPTEDJSON column. The table, in my case, has 737 rows. The last row in it looks like this (spaces & newlines removed for brevity):
Code:
737|1|1|43|2|I���F�9�f�{��1�g�P�����ʤg��F�F=�3�q�^�ߔ��X~�W�Z���X���x>�W�����\�ZQ�j�ƾ*�aAd�¹�e^���2`7�`�:O$�D�_�x�z��Xݴ�'�D�ߥ],����f�K�~tA�����.���V�ǕuA=�s�OT$1#���<#g�@�n��4��� hƳ��!��+M�`{V�ڡ3V�j�}��+�w�SdTۚ!(Ef�=_��j�� ���N��"g|°�*"��ޙ����Ȩ�8��y�H��hd��@�<Ȍvpr�{s��A��½��r�J�9&�'���x���+}���#����@:�q��Z��:ϥ&���WUt������q�
So there you go, encrypted json.
The files in "resources" seem to be straight-up binary, so they may be encrypted in some fashion.
-------------------------------------------
Okay, further down the rabbit hole!
I pulled the Kindle.app file off of my iPad with iFunbox (only possible with iOS 5). Examining the innards, I found this:
Code:
KcrBookData.momd/
├── KcrBookData.mom
├── KcrBookData.omo
└── VersionInfo.plist
These are Core Data files. Core Data is the iOS framework that can save/load information from a sqlite database. When I decompiled the MOM file with
momdec, I get an XCDATAMODEL file. Opened in Xcode, there's a "BookPiece" entity that has the fields "encryptedJson", "pieceId" and "type". There's also a "LocationMap" entity. So K4iOS is using CoreData with the book.kcr file, clearly.
There's also this:
Code:
KindleCloudReader/
├── KindleCloudReader.html
├── bridge.min.js
├── preamble.min.js
└── renderer.min.js
The
KindleCloudReader.html is a skeleton that loads in jQuery and the 3 other JS files. It looks like the HTML file would be displayed in a
UIWebView, and the <body> of that HTML file would be populated with data that is dynamically loaded.
The
preamble.js file contains some simple functions for determining what iOS platform and OS is in use (iPad, iPhone, iOS 4/5).
The
renderer.js file is
massive, and contains stuff for rendering glyphs, page turns, displaying images, zooming, building DOM, topaz stuff, default CSS styles, lists of colors, font loading, the whole nine yards. It's 8600 lines of code. Whoever made this thing is definitely a pro.
The
bridge.js file is where things get interesting. It has some sort of bridging code (go figure) between the WebView Javascript and the iOS app. First, there's an object called "KCRiOSBridge". It has a method called "openBook". In "openBook", there's a number of sub-commands such as "loadMetadata", "loadFragmap", "loadManifest", "loadSkeleton".
Why is this interesting? In the unprocessed AZK file, we have a "kcrManifest.jsonp". It looks like a javascript file with a function call, "loadManifest", using a JSON blob as an argument.
Code:
loadManifest({"json":"somejson"});
We also have "metadata.jsonp", which has the function "loadMetadata", and "rawManiest.jsonp", which calls "loadManifest" as well. All of the "resource" files begin with the function call "loadResource#", where # is the number in the resource file name. Same with the files in "frags": they have a function call "loadFragment#", and the files in "mobilocations" begin with a function call "loadMobiLocationMap#".
Well...mostly. I noticed that one of my resources is one of my original CSS files, untouched, while another resource appears to be some sort of processed version of the same CSS file. Some of them are fonts (you can see the license & trademark information as cleartext in the middle of the binary font data) and some are straight-up binary, which are probably images.
Anyway, I'm guessing that these various files are executed as javascript snippets by the KCRiOSBridge, inside a Webview. The bridging object communicates with the iOS app via requests with special protocols, such as "command" and "kcr". So you get a URL like "command://KCRPostCall". The iOS app sees that it's not a normal HTTP request like "http://google.com", then intercepts it and uses it to perform some sort of operation.
(This is a standard method of communicating between a WebView--miniature web browser embedded in an iOS app--and the app itself.)
Anyway, I might be getting over some peoples' heads at this point, but my overall
guess is that the contents of the AZK file are a series of Javascript snippets, which have the book encoded as JSON. The Javascript snippets are executed by the KCRiOSBridge, which loads the JSON data, and as bridge gets that data it is passed up to the iOS app itself. The app would then create a new "book.kcr" sqlite file, encrypt the JSON and save it into the database with Core Data. When this process is fully complete, K4iOS would destroy the AZK file and simply use the newly created KCR. This is, from what I can see, the process of converting AZK into KCR.
-----------------------------------------
Now, that doesn't really solve my problem. I may have a grasp of the process being used, but the resultant KCR that K4iOS is making is still erroring. The process is too opaque to me to divine what could be going wrong, so I'm left with three options:
- See if I can get a more useful error out of K4iOS, rather than "delete and re-download this book". This would involve jailbreaking and attaching a debugger to the app, which is something I've never done before and would be time-consuming, but enlightening.
- Compare my AZK to another and see if I can determine any differences that could cause the conversion to "succeed" and yet produce an unusable KCR.
- Hack apart my EPUB/AZK and see if I can excise a portion of it that is causing this problem.
So, that's where I stand. Any thoughts? Avenues I may have missed?