libmobi 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.clang-format +10 -0
- data/.gitignore +10 -0
- data/.rubocop.yml +26 -0
- data/.travis.yml +5 -0
- data/Gemfile +19 -0
- data/LICENSE +674 -0
- data/README.md +38 -0
- data/Rakefile +53 -0
- data/bin/console +23 -0
- data/bin/setup +23 -0
- data/ext/mobi_ext/extconf.rb +33 -0
- data/ext/mobi_ext/mobi_ext.c +909 -0
- data/lib/libmobi.rb +23 -0
- data/lib/mobi.rb +17 -0
- data/lib/mobi/book.rb +20 -0
- data/lib/mobi/error.rb +21 -0
- data/lib/mobi/version.rb +19 -0
- data/libmobi.gemspec +41 -0
- metadata +103 -0
data/README.md
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
# libmobi.rb
|
2
|
+
|
3
|
+
This is a ruby binding for library for handling Mobipocket/Kindle (MOBI) ebook format documents: https://github.com/bfabiszewski/libmobi.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'libmobi'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install libmobi
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
TODO: Write usage instructions here
|
24
|
+
|
25
|
+
## Development
|
26
|
+
|
27
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run
|
28
|
+
the tests. You can also run `bin/console` for an interactive prompt that will allow you to
|
29
|
+
experiment.
|
30
|
+
|
31
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new
|
32
|
+
version, update the version number in `version.rb`, and then run `bundle exec rake release`, which
|
33
|
+
will create a git tag for the version, push git commits and tags, and push the `.gem` file to
|
34
|
+
[rubygems.org](https://rubygems.org).
|
35
|
+
|
36
|
+
## Contributing
|
37
|
+
|
38
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/avsej/libmobi.rb.
|
data/Rakefile
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
# libmobi - library for handling Kindle (MOBI) formats of ebook documents
|
2
|
+
# Copyright (C) 2018 Sergey Avseyev <sergey.avseyev@gmail.com>
|
3
|
+
#
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
6
|
+
# the Free Software Foundation, either version 3 of the License, or
|
7
|
+
# (at your option) any later version.
|
8
|
+
#
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
16
|
+
|
17
|
+
require 'bundler/gem_tasks'
|
18
|
+
require 'rake/testtask'
|
19
|
+
|
20
|
+
module Bundler
|
21
|
+
class GemHelper
|
22
|
+
|
23
|
+
def tag_version
|
24
|
+
sh "git tag -s -m \"Version #{version}\" #{version_tag}"
|
25
|
+
Bundler.ui.confirm "Tagged #{version_tag}."
|
26
|
+
yield if block_given?
|
27
|
+
rescue
|
28
|
+
Bundler.ui.error "Untagging #{version_tag} due to error."
|
29
|
+
sh_with_code "git tag -d #{version_tag}"
|
30
|
+
raise
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
Rake::TestTask.new(:test) do |t|
|
36
|
+
t.libs << 'test'
|
37
|
+
t.libs << 'lib'
|
38
|
+
t.test_files = FileList['test/**/*_test.rb']
|
39
|
+
end
|
40
|
+
|
41
|
+
require "rake/extensiontask"
|
42
|
+
|
43
|
+
def gemspec
|
44
|
+
@clean_gemspec ||= eval(File.read(File.expand_path('libmobi.gemspec', File.dirname(__FILE__))))
|
45
|
+
end
|
46
|
+
|
47
|
+
Rake::ExtensionTask.new("mobi_ext", gemspec) do |ext|
|
48
|
+
ext.ext_dir = "ext/mobi_ext"
|
49
|
+
CLEAN.include "#{ext.lib_dir}/*.#{RbConfig::CONFIG['DLEXT']}"
|
50
|
+
end
|
51
|
+
Rake::Task['test'].prerequisites.unshift('compile')
|
52
|
+
|
53
|
+
task :default => :test
|
data/bin/console
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# libmobi - library for handling Kindle (MOBI) formats of ebook documents
|
4
|
+
# Copyright (C) 2018 Sergey Avseyev <sergey.avseyev@gmail.com>
|
5
|
+
#
|
6
|
+
# This program is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU General Public License as published by
|
8
|
+
# the Free Software Foundation, either version 3 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
#
|
11
|
+
# This program is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU General Public License
|
17
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
18
|
+
|
19
|
+
require 'bundler/setup'
|
20
|
+
require 'libmobi'
|
21
|
+
|
22
|
+
require 'irb'
|
23
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
|
3
|
+
# libmobi - library for handling Kindle (MOBI) formats of ebook documents
|
4
|
+
# Copyright (C) 2018 Sergey Avseyev <sergey.avseyev@gmail.com>
|
5
|
+
#
|
6
|
+
# This program is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU General Public License as published by
|
8
|
+
# the Free Software Foundation, either version 3 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
#
|
11
|
+
# This program is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU General Public License
|
17
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
18
|
+
|
19
|
+
set -euo pipefail
|
20
|
+
IFS=$'\n\t'
|
21
|
+
set -vx
|
22
|
+
|
23
|
+
bundle install
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# libmobi - library for handling Kindle (MOBI) formats of ebook documents
|
2
|
+
# Copyright (C) 2018 Sergey Avseyev <sergey.avseyev@gmail.com>
|
3
|
+
#
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
6
|
+
# the Free Software Foundation, either version 3 of the License, or
|
7
|
+
# (at your option) any later version.
|
8
|
+
#
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
12
|
+
# GNU General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU General Public License
|
15
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
16
|
+
|
17
|
+
require 'rbconfig'
|
18
|
+
require 'mkmf'
|
19
|
+
|
20
|
+
def define(macro, value = nil)
|
21
|
+
$defs.push("-D #{[macro.upcase, Shellwords.shellescape(value)].compact.join('=')}")
|
22
|
+
end
|
23
|
+
|
24
|
+
pkg_config('libmobi') || abort('libmobi headers not found. (dnf install libmobi-devel on Fedora)')
|
25
|
+
|
26
|
+
$CFLAGS << ' -pedantic -Wall -Wextra -Werror '
|
27
|
+
if ENV['DEBUG_BUILD']
|
28
|
+
$CFLAGS.gsub!(/\W-Wp,-D_FORTIFY_SOURCE=\d+\W/, ' ')
|
29
|
+
$CFLAGS << ' -ggdb3 -O0 '
|
30
|
+
end
|
31
|
+
|
32
|
+
create_header('mobi_config.h')
|
33
|
+
create_makefile('mobi_ext')
|
@@ -0,0 +1,909 @@
|
|
1
|
+
/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
2
|
+
|
3
|
+
#include <mobi.h>
|
4
|
+
|
5
|
+
#include <ruby.h>
|
6
|
+
|
7
|
+
VALUE mb_mMOBI;
|
8
|
+
VALUE mb_eError;
|
9
|
+
VALUE mb_cBook;
|
10
|
+
|
11
|
+
static const char *mb_libmobi_strerror(MOBI_RET code)
|
12
|
+
{
|
13
|
+
switch (code) {
|
14
|
+
case MOBI_ERROR:
|
15
|
+
return "generic error return value";
|
16
|
+
case MOBI_PARAM_ERR:
|
17
|
+
return "wrong function parameter";
|
18
|
+
case MOBI_DATA_CORRUPT:
|
19
|
+
return "corrupted data";
|
20
|
+
case MOBI_FILE_NOT_FOUND:
|
21
|
+
return "file not found";
|
22
|
+
case MOBI_FILE_ENCRYPTED:
|
23
|
+
return "unsupported encrypted data";
|
24
|
+
case MOBI_FILE_UNSUPPORTED:
|
25
|
+
return "unsupported document type";
|
26
|
+
case MOBI_MALLOC_FAILED:
|
27
|
+
return "memory allocation error";
|
28
|
+
case MOBI_INIT_FAILED:
|
29
|
+
return "initialization error";
|
30
|
+
case MOBI_BUFFER_END:
|
31
|
+
return "out of buffer error";
|
32
|
+
case MOBI_XML_ERR:
|
33
|
+
return "XMLwriter error";
|
34
|
+
case MOBI_DRM_PIDINV:
|
35
|
+
return "invalid DRM PID";
|
36
|
+
case MOBI_DRM_KEYNOTFOUND:
|
37
|
+
return "key not found";
|
38
|
+
case MOBI_DRM_UNSUPPORTED:
|
39
|
+
return "DRM support not included";
|
40
|
+
case MOBI_WRITE_FAILED:
|
41
|
+
return "writing to file failed";
|
42
|
+
default:
|
43
|
+
return "FIXME: unkwnown code";
|
44
|
+
}
|
45
|
+
}
|
46
|
+
|
47
|
+
static void mb_raise_at(MOBI_RET code, const char *message, const char *file, int line)
|
48
|
+
{
|
49
|
+
VALUE exc, str;
|
50
|
+
|
51
|
+
str = rb_str_new_cstr(message);
|
52
|
+
if (code > 0) {
|
53
|
+
rb_str_catf(str, ": (0x%02x) \"%s\"", (int)code, mb_libmobi_strerror(code));
|
54
|
+
}
|
55
|
+
rb_str_buf_cat_ascii(str, " at ");
|
56
|
+
rb_str_buf_cat_ascii(str, file);
|
57
|
+
rb_str_catf(str, ":%d", line);
|
58
|
+
exc = rb_exc_new3(mb_eError, str);
|
59
|
+
rb_ivar_set(exc, rb_intern("@code"), INT2FIX(code));
|
60
|
+
rb_exc_raise(exc);
|
61
|
+
}
|
62
|
+
|
63
|
+
#define mb_raise(code, message) mb_raise_at(code, message, __FILE__, __LINE__)
|
64
|
+
#define mb_raise_msg(message) mb_raise_at(0, message, __FILE__, __LINE__)
|
65
|
+
|
66
|
+
typedef struct mb_BOOK {
|
67
|
+
MOBIData *data;
|
68
|
+
} mb_BOOK;
|
69
|
+
|
70
|
+
static void mb_book_mark(void *ptr)
|
71
|
+
{
|
72
|
+
mb_BOOK *book = ptr;
|
73
|
+
(void)book;
|
74
|
+
}
|
75
|
+
|
76
|
+
static void mb_book_free(void *ptr)
|
77
|
+
{
|
78
|
+
mb_BOOK *book = ptr;
|
79
|
+
if (book) {
|
80
|
+
if (book->data) {
|
81
|
+
mobi_free(book->data);
|
82
|
+
}
|
83
|
+
book->data = NULL;
|
84
|
+
}
|
85
|
+
}
|
86
|
+
|
87
|
+
static VALUE mb_book_alloc(VALUE klass)
|
88
|
+
{
|
89
|
+
VALUE obj;
|
90
|
+
mb_BOOK *book;
|
91
|
+
|
92
|
+
obj = Data_Make_Struct(klass, mb_BOOK, mb_book_mark, mb_book_free, book);
|
93
|
+
return obj;
|
94
|
+
}
|
95
|
+
|
96
|
+
static VALUE mb_book_init(VALUE self, VALUE path)
|
97
|
+
{
|
98
|
+
mb_BOOK *book = DATA_PTR(self);
|
99
|
+
MOBI_RET rc;
|
100
|
+
|
101
|
+
Check_Type(path, T_STRING);
|
102
|
+
|
103
|
+
book->data = mobi_init();
|
104
|
+
if (book->data == NULL) {
|
105
|
+
mb_raise(MOBI_MALLOC_FAILED, "unable to allocate MOBIData struct");
|
106
|
+
}
|
107
|
+
|
108
|
+
rc = mobi_load_filename(book->data, RSTRING_PTR(path));
|
109
|
+
if (rc != MOBI_SUCCESS) {
|
110
|
+
mb_raise(rc, "unable to load book from path");
|
111
|
+
}
|
112
|
+
return self;
|
113
|
+
}
|
114
|
+
|
115
|
+
static VALUE mb_book_next(VALUE self)
|
116
|
+
{
|
117
|
+
mb_BOOK *book = DATA_PTR(self);
|
118
|
+
|
119
|
+
if (book == NULL || book->data == NULL) {
|
120
|
+
mb_raise(MOBI_INIT_FAILED, "the MOBI data is not loaded");
|
121
|
+
}
|
122
|
+
if (mobi_is_hybrid(book->data) && book->data->next != NULL) {
|
123
|
+
VALUE obj;
|
124
|
+
mb_BOOK *next;
|
125
|
+
|
126
|
+
obj = Data_Make_Struct(mb_cBook, mb_BOOK, mb_book_mark, mb_book_free, next);
|
127
|
+
next->data = book->data->next;
|
128
|
+
return obj;
|
129
|
+
}
|
130
|
+
|
131
|
+
return Qnil;
|
132
|
+
}
|
133
|
+
|
134
|
+
#define COPY_HEADER_INT(NAME) \
|
135
|
+
if (hdr->NAME) { \
|
136
|
+
rb_hash_aset(res, ID2SYM(rb_intern(#NAME)), INT2FIX(*hdr->NAME)); \
|
137
|
+
}
|
138
|
+
static VALUE mb_book_mobi_header(VALUE self)
|
139
|
+
{
|
140
|
+
mb_BOOK *book = DATA_PTR(self);
|
141
|
+
VALUE res;
|
142
|
+
MOBIMobiHeader *hdr;
|
143
|
+
|
144
|
+
if (book == NULL || book->data == NULL) {
|
145
|
+
mb_raise(MOBI_INIT_FAILED, "the MOBI data is not loaded");
|
146
|
+
}
|
147
|
+
hdr = book->data->mh;
|
148
|
+
if (hdr == NULL) {
|
149
|
+
return Qnil;
|
150
|
+
}
|
151
|
+
|
152
|
+
res = rb_hash_new();
|
153
|
+
rb_hash_aset(res, ID2SYM(rb_intern("magic")), rb_str_new_cstr(hdr->mobi_magic));
|
154
|
+
COPY_HEADER_INT(header_length);
|
155
|
+
COPY_HEADER_INT(mobi_type);
|
156
|
+
if (hdr->text_encoding) {
|
157
|
+
rb_hash_aset(res, ID2SYM(rb_intern("text_encoding")), INT2FIX(*hdr->text_encoding));
|
158
|
+
switch (*hdr->text_encoding) {
|
159
|
+
case MOBI_CP1252:
|
160
|
+
rb_hash_aset(res, ID2SYM(rb_intern("text_encoding_sym")), ID2SYM(rb_intern("cp1252")));
|
161
|
+
break;
|
162
|
+
case MOBI_UTF8:
|
163
|
+
rb_hash_aset(res, ID2SYM(rb_intern("text_encoding_sym")), ID2SYM(rb_intern("utf8")));
|
164
|
+
break;
|
165
|
+
case MOBI_UTF16:
|
166
|
+
rb_hash_aset(res, ID2SYM(rb_intern("text_encoding_sym")), ID2SYM(rb_intern("utf16")));
|
167
|
+
break;
|
168
|
+
default:
|
169
|
+
rb_hash_aset(res, ID2SYM(rb_intern("text_encoding_sym")), ID2SYM(rb_intern("unknown")));
|
170
|
+
break;
|
171
|
+
}
|
172
|
+
}
|
173
|
+
if (hdr->locale) {
|
174
|
+
const char *locale_string = mobi_get_locale_string(*hdr->locale);
|
175
|
+
if (locale_string) {
|
176
|
+
rb_hash_aset(res, ID2SYM(rb_intern("locale_str")), rb_str_new_cstr(locale_string));
|
177
|
+
}
|
178
|
+
rb_hash_aset(res, ID2SYM(rb_intern("locale")), INT2FIX(*hdr->locale));
|
179
|
+
}
|
180
|
+
if (hdr->dict_input_lang) {
|
181
|
+
const char *locale_string = mobi_get_locale_string(*hdr->dict_input_lang);
|
182
|
+
if (locale_string) {
|
183
|
+
rb_hash_aset(res, ID2SYM(rb_intern("dict_input_lang_str")), rb_str_new_cstr(locale_string));
|
184
|
+
}
|
185
|
+
rb_hash_aset(res, ID2SYM(rb_intern("dict_input_lang")), INT2FIX(*hdr->dict_input_lang));
|
186
|
+
}
|
187
|
+
if (hdr->dict_output_lang) {
|
188
|
+
const char *locale_string = mobi_get_locale_string(*hdr->dict_output_lang);
|
189
|
+
if (locale_string) {
|
190
|
+
rb_hash_aset(res, ID2SYM(rb_intern("dict_output_lang_str")), rb_str_new_cstr(locale_string));
|
191
|
+
}
|
192
|
+
rb_hash_aset(res, ID2SYM(rb_intern("dict_output_lang")), INT2FIX(*hdr->dict_output_lang));
|
193
|
+
}
|
194
|
+
COPY_HEADER_INT(uid);
|
195
|
+
COPY_HEADER_INT(version);
|
196
|
+
COPY_HEADER_INT(orth_index);
|
197
|
+
COPY_HEADER_INT(infl_index);
|
198
|
+
COPY_HEADER_INT(names_index);
|
199
|
+
COPY_HEADER_INT(keys_index);
|
200
|
+
COPY_HEADER_INT(keys_index);
|
201
|
+
COPY_HEADER_INT(extra0_index);
|
202
|
+
COPY_HEADER_INT(extra1_index);
|
203
|
+
COPY_HEADER_INT(extra2_index);
|
204
|
+
COPY_HEADER_INT(extra3_index);
|
205
|
+
COPY_HEADER_INT(extra4_index);
|
206
|
+
COPY_HEADER_INT(extra5_index);
|
207
|
+
COPY_HEADER_INT(non_text_index);
|
208
|
+
COPY_HEADER_INT(full_name_offset);
|
209
|
+
COPY_HEADER_INT(full_name_length);
|
210
|
+
COPY_HEADER_INT(min_version);
|
211
|
+
COPY_HEADER_INT(image_index);
|
212
|
+
COPY_HEADER_INT(huff_rec_index);
|
213
|
+
COPY_HEADER_INT(huff_rec_count);
|
214
|
+
COPY_HEADER_INT(datp_rec_index);
|
215
|
+
COPY_HEADER_INT(datp_rec_count);
|
216
|
+
COPY_HEADER_INT(exth_flags);
|
217
|
+
COPY_HEADER_INT(unknown6);
|
218
|
+
COPY_HEADER_INT(drm_offset);
|
219
|
+
COPY_HEADER_INT(drm_count);
|
220
|
+
COPY_HEADER_INT(drm_size);
|
221
|
+
COPY_HEADER_INT(drm_flags);
|
222
|
+
COPY_HEADER_INT(first_text_index);
|
223
|
+
COPY_HEADER_INT(last_text_index);
|
224
|
+
COPY_HEADER_INT(fdst_index);
|
225
|
+
COPY_HEADER_INT(fdst_section_count);
|
226
|
+
COPY_HEADER_INT(fcis_index);
|
227
|
+
COPY_HEADER_INT(fcis_count);
|
228
|
+
COPY_HEADER_INT(flis_index);
|
229
|
+
COPY_HEADER_INT(flis_count);
|
230
|
+
COPY_HEADER_INT(unknown10);
|
231
|
+
COPY_HEADER_INT(unknown11);
|
232
|
+
COPY_HEADER_INT(srcs_index);
|
233
|
+
COPY_HEADER_INT(srcs_count);
|
234
|
+
COPY_HEADER_INT(unknown12);
|
235
|
+
COPY_HEADER_INT(unknown13);
|
236
|
+
COPY_HEADER_INT(extra_flags);
|
237
|
+
COPY_HEADER_INT(ncx_index);
|
238
|
+
COPY_HEADER_INT(unknown14);
|
239
|
+
COPY_HEADER_INT(unknown15);
|
240
|
+
COPY_HEADER_INT(fragment_index);
|
241
|
+
COPY_HEADER_INT(skeleton_index);
|
242
|
+
COPY_HEADER_INT(datp_index);
|
243
|
+
COPY_HEADER_INT(unknown16);
|
244
|
+
COPY_HEADER_INT(guide_index);
|
245
|
+
COPY_HEADER_INT(unknown17);
|
246
|
+
COPY_HEADER_INT(unknown18);
|
247
|
+
COPY_HEADER_INT(unknown19);
|
248
|
+
COPY_HEADER_INT(unknown20);
|
249
|
+
|
250
|
+
return res;
|
251
|
+
}
|
252
|
+
#undef COPY_HEADER_INT
|
253
|
+
|
254
|
+
static VALUE mb_book_pdb_header(VALUE self)
|
255
|
+
{
|
256
|
+
mb_BOOK *book = DATA_PTR(self);
|
257
|
+
VALUE res;
|
258
|
+
MOBIPdbHeader *hdr;
|
259
|
+
|
260
|
+
if (book == NULL || book->data == NULL) {
|
261
|
+
mb_raise(MOBI_INIT_FAILED, "the MOBI data is not loaded");
|
262
|
+
}
|
263
|
+
hdr = book->data->ph;
|
264
|
+
if (hdr == NULL) {
|
265
|
+
return Qnil;
|
266
|
+
}
|
267
|
+
res = rb_hash_new();
|
268
|
+
rb_hash_aset(res, ID2SYM(rb_intern("name")), rb_str_new_cstr(hdr->name));
|
269
|
+
rb_hash_aset(res, ID2SYM(rb_intern("attributes")), INT2FIX(hdr->attributes));
|
270
|
+
rb_hash_aset(res, ID2SYM(rb_intern("version")), INT2FIX(hdr->version));
|
271
|
+
rb_hash_aset(res, ID2SYM(rb_intern("ctime")), INT2FIX(hdr->ctime));
|
272
|
+
if (hdr->ctime) {
|
273
|
+
rb_hash_aset(res, ID2SYM(rb_intern("ctime_time")), rb_time_new(mktime(mobi_pdbtime_to_time(hdr->ctime)), 0));
|
274
|
+
}
|
275
|
+
rb_hash_aset(res, ID2SYM(rb_intern("mtime")), INT2FIX(hdr->mtime));
|
276
|
+
if (hdr->mtime) {
|
277
|
+
rb_hash_aset(res, ID2SYM(rb_intern("mtime_time")), rb_time_new(mktime(mobi_pdbtime_to_time(hdr->mtime)), 0));
|
278
|
+
}
|
279
|
+
rb_hash_aset(res, ID2SYM(rb_intern("btime")), INT2FIX(hdr->btime));
|
280
|
+
if (hdr->btime) {
|
281
|
+
rb_hash_aset(res, ID2SYM(rb_intern("btime_time")), rb_time_new(mktime(mobi_pdbtime_to_time(hdr->btime)), 0));
|
282
|
+
}
|
283
|
+
rb_hash_aset(res, ID2SYM(rb_intern("mod_num")), INT2FIX(hdr->mod_num));
|
284
|
+
rb_hash_aset(res, ID2SYM(rb_intern("appinfo_offset")), INT2FIX(hdr->appinfo_offset));
|
285
|
+
rb_hash_aset(res, ID2SYM(rb_intern("sortinfo_offset")), INT2FIX(hdr->sortinfo_offset));
|
286
|
+
rb_hash_aset(res, ID2SYM(rb_intern("type")), rb_str_new_cstr(hdr->type));
|
287
|
+
rb_hash_aset(res, ID2SYM(rb_intern("creator")), rb_str_new_cstr(hdr->creator));
|
288
|
+
rb_hash_aset(res, ID2SYM(rb_intern("uid")), INT2FIX(hdr->uid));
|
289
|
+
rb_hash_aset(res, ID2SYM(rb_intern("next_rec")), INT2FIX(hdr->next_rec));
|
290
|
+
rb_hash_aset(res, ID2SYM(rb_intern("rec_count")), INT2FIX(hdr->rec_count));
|
291
|
+
return res;
|
292
|
+
}
|
293
|
+
|
294
|
+
static VALUE mb_book_record0_header(VALUE self)
|
295
|
+
{
|
296
|
+
mb_BOOK *book = DATA_PTR(self);
|
297
|
+
VALUE res;
|
298
|
+
MOBIRecord0Header *hdr;
|
299
|
+
|
300
|
+
if (book == NULL || book->data == NULL) {
|
301
|
+
mb_raise(MOBI_INIT_FAILED, "the MOBI data is not loaded");
|
302
|
+
}
|
303
|
+
hdr = book->data->rh;
|
304
|
+
if (hdr == NULL) {
|
305
|
+
return Qnil;
|
306
|
+
}
|
307
|
+
|
308
|
+
res = rb_hash_new();
|
309
|
+
rb_hash_aset(res, ID2SYM(rb_intern("compression_type")), INT2FIX(hdr->compression_type));
|
310
|
+
switch (hdr->compression_type) {
|
311
|
+
case 1:
|
312
|
+
rb_hash_aset(res, ID2SYM(rb_intern("compression_type_sym")), ID2SYM(rb_intern("none")));
|
313
|
+
break;
|
314
|
+
case 2:
|
315
|
+
rb_hash_aset(res, ID2SYM(rb_intern("compression_type_sym")), ID2SYM(rb_intern("palm_doc")));
|
316
|
+
break;
|
317
|
+
case 17480:
|
318
|
+
rb_hash_aset(res, ID2SYM(rb_intern("compression_type_sym")), ID2SYM(rb_intern("huff_cdic")));
|
319
|
+
break;
|
320
|
+
}
|
321
|
+
rb_hash_aset(res, ID2SYM(rb_intern("text_length")), INT2FIX(hdr->text_length));
|
322
|
+
rb_hash_aset(res, ID2SYM(rb_intern("text_record_count")), INT2FIX(hdr->text_record_count));
|
323
|
+
rb_hash_aset(res, ID2SYM(rb_intern("text_record_size")), INT2FIX(hdr->text_record_size));
|
324
|
+
rb_hash_aset(res, ID2SYM(rb_intern("encryption_type")), INT2FIX(hdr->encryption_type));
|
325
|
+
switch (hdr->encryption_type) {
|
326
|
+
case 0:
|
327
|
+
rb_hash_aset(res, ID2SYM(rb_intern("encryption_type_sym")), ID2SYM(rb_intern("none")));
|
328
|
+
break;
|
329
|
+
case 1:
|
330
|
+
rb_hash_aset(res, ID2SYM(rb_intern("encryption_type_sym")), ID2SYM(rb_intern("old")));
|
331
|
+
break;
|
332
|
+
case 2:
|
333
|
+
rb_hash_aset(res, ID2SYM(rb_intern("encryption_type_sym")), ID2SYM(rb_intern("mobi")));
|
334
|
+
break;
|
335
|
+
}
|
336
|
+
rb_hash_aset(res, ID2SYM(rb_intern("unknown1")), INT2FIX(hdr->unknown1));
|
337
|
+
return res;
|
338
|
+
}
|
339
|
+
|
340
|
+
static VALUE mb_book_exth_header(VALUE self)
|
341
|
+
{
|
342
|
+
mb_BOOK *book = DATA_PTR(self);
|
343
|
+
VALUE res;
|
344
|
+
MOBIExthHeader *hdr;
|
345
|
+
|
346
|
+
if (book == NULL || book->data == NULL) {
|
347
|
+
mb_raise(MOBI_INIT_FAILED, "the MOBI data is not loaded");
|
348
|
+
}
|
349
|
+
hdr = book->data->eh;
|
350
|
+
if (hdr == NULL) {
|
351
|
+
return Qnil;
|
352
|
+
}
|
353
|
+
|
354
|
+
res = rb_ary_new();
|
355
|
+
while (hdr != NULL) {
|
356
|
+
MOBIExthMeta tag = mobi_get_exthtagmeta_by_tag(hdr->tag);
|
357
|
+
uint32_t val32;
|
358
|
+
VALUE item = rb_hash_new();
|
359
|
+
|
360
|
+
rb_hash_aset(item, ID2SYM(rb_intern("code")), INT2FIX(tag.tag));
|
361
|
+
switch (hdr->tag) {
|
362
|
+
case EXTH_SAMPLE:
|
363
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("sample")));
|
364
|
+
break;
|
365
|
+
case EXTH_STARTREADING:
|
366
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("start_reading")));
|
367
|
+
break;
|
368
|
+
case EXTH_KF8BOUNDARY:
|
369
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("kf8_boundary")));
|
370
|
+
break;
|
371
|
+
case EXTH_COUNTRESOURCES:
|
372
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("count_resources")));
|
373
|
+
break;
|
374
|
+
case EXTH_RESCOFFSET:
|
375
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("resc_offset")));
|
376
|
+
break;
|
377
|
+
case EXTH_COVEROFFSET:
|
378
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("cover_offset")));
|
379
|
+
break;
|
380
|
+
case EXTH_THUMBOFFSET:
|
381
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("thumb_offset")));
|
382
|
+
break;
|
383
|
+
case EXTH_HASFAKECOVER:
|
384
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("has_fake_cover")));
|
385
|
+
break;
|
386
|
+
case EXTH_CREATORSOFT:
|
387
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("creator_soft")));
|
388
|
+
break;
|
389
|
+
case EXTH_CREATORMAJOR:
|
390
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("creator_major")));
|
391
|
+
break;
|
392
|
+
case EXTH_CREATORMINOR:
|
393
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("creator_minor")));
|
394
|
+
break;
|
395
|
+
case EXTH_CREATORBUILD:
|
396
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("creator_build")));
|
397
|
+
break;
|
398
|
+
case EXTH_CLIPPINGLIMIT:
|
399
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("clipping_limit")));
|
400
|
+
break;
|
401
|
+
case EXTH_PUBLISHERLIMIT:
|
402
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("publisher_limit")));
|
403
|
+
break;
|
404
|
+
case EXTH_TTSDISABLE:
|
405
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("tts_disabled")));
|
406
|
+
break;
|
407
|
+
case EXTH_RENTAL:
|
408
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("rental")));
|
409
|
+
break;
|
410
|
+
case EXTH_DRMSERVER:
|
411
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("drm_server")));
|
412
|
+
break;
|
413
|
+
case EXTH_DRMCOMMERCE:
|
414
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("drm_commerce")));
|
415
|
+
break;
|
416
|
+
case EXTH_DRMEBOOKBASE:
|
417
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("drm_ebookbase")));
|
418
|
+
break;
|
419
|
+
case EXTH_TITLE:
|
420
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("title")));
|
421
|
+
break;
|
422
|
+
case EXTH_AUTHOR:
|
423
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("creator")));
|
424
|
+
break;
|
425
|
+
case EXTH_PUBLISHER:
|
426
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("publisher")));
|
427
|
+
break;
|
428
|
+
case EXTH_IMPRINT:
|
429
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("imprint")));
|
430
|
+
break;
|
431
|
+
case EXTH_DESCRIPTION:
|
432
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("description")));
|
433
|
+
break;
|
434
|
+
case EXTH_ISBN:
|
435
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("isbn")));
|
436
|
+
break;
|
437
|
+
case EXTH_SUBJECT:
|
438
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("subject")));
|
439
|
+
break;
|
440
|
+
case EXTH_PUBLISHINGDATE:
|
441
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("published")));
|
442
|
+
break;
|
443
|
+
case EXTH_REVIEW:
|
444
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("review")));
|
445
|
+
break;
|
446
|
+
case EXTH_CONTRIBUTOR:
|
447
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("contributor")));
|
448
|
+
break;
|
449
|
+
case EXTH_RIGHTS:
|
450
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("rights")));
|
451
|
+
break;
|
452
|
+
case EXTH_SUBJECTCODE:
|
453
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("subject_code")));
|
454
|
+
break;
|
455
|
+
case EXTH_TYPE:
|
456
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("type")));
|
457
|
+
break;
|
458
|
+
case EXTH_SOURCE:
|
459
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("source")));
|
460
|
+
break;
|
461
|
+
case EXTH_ASIN:
|
462
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("asin")));
|
463
|
+
break;
|
464
|
+
case EXTH_VERSION:
|
465
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("version")));
|
466
|
+
break;
|
467
|
+
case EXTH_ADULT:
|
468
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("adult")));
|
469
|
+
break;
|
470
|
+
case EXTH_PRICE:
|
471
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("price")));
|
472
|
+
break;
|
473
|
+
case EXTH_CURRENCY:
|
474
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("currency")));
|
475
|
+
break;
|
476
|
+
case EXTH_FIXEDLAYOUT:
|
477
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("fixed_layout")));
|
478
|
+
break;
|
479
|
+
case EXTH_BOOKTYPE:
|
480
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("book_type")));
|
481
|
+
break;
|
482
|
+
case EXTH_ORIENTATIONLOCK:
|
483
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("orientation_lock")));
|
484
|
+
break;
|
485
|
+
case EXTH_ORIGRESOLUTION:
|
486
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("orig_resolution")));
|
487
|
+
break;
|
488
|
+
case EXTH_ZEROGUTTER:
|
489
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("zero_gutter")));
|
490
|
+
break;
|
491
|
+
case EXTH_ZEROMARGIN:
|
492
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("zero_margin")));
|
493
|
+
break;
|
494
|
+
case EXTH_KF8COVERURI:
|
495
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("kf8_cover_uri")));
|
496
|
+
break;
|
497
|
+
case EXTH_REGIONMAGNI:
|
498
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("region_magnification")));
|
499
|
+
break;
|
500
|
+
case EXTH_DICTNAME:
|
501
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("dict_name")));
|
502
|
+
break;
|
503
|
+
case EXTH_WATERMARK:
|
504
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("watermark")));
|
505
|
+
break;
|
506
|
+
case EXTH_DOCTYPE:
|
507
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("doc_type")));
|
508
|
+
break;
|
509
|
+
case EXTH_LASTUPDATE:
|
510
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("last_update")));
|
511
|
+
break;
|
512
|
+
case EXTH_UPDATEDTITLE:
|
513
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("updated_title")));
|
514
|
+
break;
|
515
|
+
case EXTH_ASIN504:
|
516
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("asin_504")));
|
517
|
+
break;
|
518
|
+
case EXTH_TITLEFILEAS:
|
519
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("title_file_as")));
|
520
|
+
break;
|
521
|
+
case EXTH_CREATORFILEAS:
|
522
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("creator_file_as")));
|
523
|
+
break;
|
524
|
+
case EXTH_PUBLISHERFILEAS:
|
525
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("publisher_file_as")));
|
526
|
+
break;
|
527
|
+
case EXTH_LANGUAGE:
|
528
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("language")));
|
529
|
+
break;
|
530
|
+
case EXTH_ALIGNMENT:
|
531
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("alignment")));
|
532
|
+
break;
|
533
|
+
case EXTH_PAGEDIR:
|
534
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("page_dir")));
|
535
|
+
break;
|
536
|
+
case EXTH_OVERRIDEFONTS:
|
537
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("override_fonts")));
|
538
|
+
break;
|
539
|
+
case EXTH_SORCEDESC:
|
540
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("source_desc")));
|
541
|
+
break;
|
542
|
+
case EXTH_DICTLANGIN:
|
543
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("dict_lang_in")));
|
544
|
+
break;
|
545
|
+
case EXTH_DICTLANGOUT:
|
546
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("dict_lang_out")));
|
547
|
+
break;
|
548
|
+
case EXTH_INPUTSOURCE:
|
549
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("input_source")));
|
550
|
+
break;
|
551
|
+
case EXTH_CREATORBUILDREV:
|
552
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("creator_build_rev")));
|
553
|
+
break;
|
554
|
+
case EXTH_CREATORSTRING:
|
555
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("creator_string")));
|
556
|
+
break;
|
557
|
+
case EXTH_TAMPERKEYS:
|
558
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("tamper_keys")));
|
559
|
+
break;
|
560
|
+
case EXTH_FONTSIGNATURE:
|
561
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("font_signature")));
|
562
|
+
break;
|
563
|
+
case EXTH_UNK403:
|
564
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("unknown_403")));
|
565
|
+
break;
|
566
|
+
case EXTH_UNK405:
|
567
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("unknown_405")));
|
568
|
+
break;
|
569
|
+
case EXTH_UNK407:
|
570
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("unknown_407")));
|
571
|
+
break;
|
572
|
+
case EXTH_UNK450:
|
573
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("unknown_450")));
|
574
|
+
break;
|
575
|
+
case EXTH_UNK451:
|
576
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("unknown_451")));
|
577
|
+
break;
|
578
|
+
case EXTH_UNK452:
|
579
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("unknown_452")));
|
580
|
+
break;
|
581
|
+
case EXTH_UNK453:
|
582
|
+
rb_hash_aset(item, ID2SYM(rb_intern("id")), ID2SYM(rb_intern("unknown_453")));
|
583
|
+
break;
|
584
|
+
}
|
585
|
+
if (tag.tag == 0) {
|
586
|
+
rb_hash_aset(item, ID2SYM(rb_intern("val_bin")), rb_str_new((const char *)hdr->data, hdr->size));
|
587
|
+
val32 = mobi_decode_exthvalue(hdr->data, hdr->size);
|
588
|
+
rb_hash_aset(item, ID2SYM(rb_intern("val_num")), INT2FIX(val32));
|
589
|
+
} else {
|
590
|
+
char *str;
|
591
|
+
rb_hash_aset(item, ID2SYM(rb_intern("name")), rb_str_new_cstr(tag.name));
|
592
|
+
switch (tag.type) {
|
593
|
+
case EXTH_NUMERIC:
|
594
|
+
val32 = mobi_decode_exthvalue(hdr->data, hdr->size);
|
595
|
+
rb_hash_aset(item, ID2SYM(rb_intern("val_num")), INT2FIX(val32));
|
596
|
+
break;
|
597
|
+
case EXTH_STRING:
|
598
|
+
str = mobi_decode_exthstring(book->data, hdr->data, hdr->size);
|
599
|
+
if (str) {
|
600
|
+
rb_hash_aset(item, ID2SYM(rb_intern("val_str")), rb_str_new_cstr(str));
|
601
|
+
free(str);
|
602
|
+
}
|
603
|
+
break;
|
604
|
+
case EXTH_BINARY:
|
605
|
+
rb_hash_aset(item, ID2SYM(rb_intern("val_bin")), rb_str_new((const char *)hdr->data, hdr->size));
|
606
|
+
break;
|
607
|
+
default:
|
608
|
+
break;
|
609
|
+
}
|
610
|
+
}
|
611
|
+
rb_ary_push(res, item);
|
612
|
+
hdr = hdr->next;
|
613
|
+
}
|
614
|
+
return res;
|
615
|
+
}
|
616
|
+
|
617
|
+
#define FULL_NAME_MAX 1024
|
618
|
+
static VALUE mb_book_full_name(VALUE self)
|
619
|
+
{
|
620
|
+
mb_BOOK *book = DATA_PTR(self);
|
621
|
+
MOBI_RET rc;
|
622
|
+
char full_name[FULL_NAME_MAX + 1] = {0};
|
623
|
+
|
624
|
+
if (book == NULL || book->data == NULL) {
|
625
|
+
mb_raise(MOBI_INIT_FAILED, "the MOBI data is not loaded");
|
626
|
+
}
|
627
|
+
rc = mobi_get_fullname(book->data, full_name, FULL_NAME_MAX);
|
628
|
+
if (rc != MOBI_SUCCESS) {
|
629
|
+
mb_raise(rc, "unable to fetch book full name");
|
630
|
+
}
|
631
|
+
return rb_str_new_cstr(full_name);
|
632
|
+
}
|
633
|
+
#undef FULL_NAME_MAX
|
634
|
+
|
635
|
+
#define DEFINE_META_GETTER_STR(ATTR) \
|
636
|
+
static VALUE mb_book_##ATTR(VALUE self) \
|
637
|
+
{ \
|
638
|
+
mb_BOOK *book = DATA_PTR(self); \
|
639
|
+
const char *str; \
|
640
|
+
\
|
641
|
+
if (book == NULL || book->data == NULL) { \
|
642
|
+
mb_raise(MOBI_INIT_FAILED, "the MOBI data is not loaded"); \
|
643
|
+
} \
|
644
|
+
str = mobi_meta_get_##ATTR(book->data); \
|
645
|
+
if (str) { \
|
646
|
+
return rb_str_new_cstr(str); \
|
647
|
+
} \
|
648
|
+
return Qnil; \
|
649
|
+
}
|
650
|
+
|
651
|
+
DEFINE_META_GETTER_STR(title)
|
652
|
+
DEFINE_META_GETTER_STR(author)
|
653
|
+
DEFINE_META_GETTER_STR(publisher)
|
654
|
+
DEFINE_META_GETTER_STR(imprint)
|
655
|
+
DEFINE_META_GETTER_STR(description)
|
656
|
+
DEFINE_META_GETTER_STR(isbn)
|
657
|
+
DEFINE_META_GETTER_STR(subject)
|
658
|
+
DEFINE_META_GETTER_STR(publishdate)
|
659
|
+
DEFINE_META_GETTER_STR(review)
|
660
|
+
DEFINE_META_GETTER_STR(contributor)
|
661
|
+
DEFINE_META_GETTER_STR(copyright)
|
662
|
+
DEFINE_META_GETTER_STR(asin)
|
663
|
+
DEFINE_META_GETTER_STR(language)
|
664
|
+
|
665
|
+
#define DEFINE_PREDICATE(METHOD, FUNCTION) \
|
666
|
+
static VALUE mb_book_p_##METHOD(VALUE self) \
|
667
|
+
{ \
|
668
|
+
mb_BOOK *book = DATA_PTR(self); \
|
669
|
+
\
|
670
|
+
if (book == NULL || book->data == NULL) { \
|
671
|
+
mb_raise(MOBI_INIT_FAILED, "the MOBI data is not loaded"); \
|
672
|
+
} \
|
673
|
+
if (FUNCTION(book->data)) { \
|
674
|
+
return Qtrue; \
|
675
|
+
} \
|
676
|
+
return Qfalse; \
|
677
|
+
}
|
678
|
+
|
679
|
+
DEFINE_PREDICATE(has_mobi_header, mobi_exists_mobiheader)
|
680
|
+
DEFINE_PREDICATE(has_fdst, mobi_exists_fdst)
|
681
|
+
DEFINE_PREDICATE(has_skeleton_index, mobi_exists_skel_indx)
|
682
|
+
DEFINE_PREDICATE(has_fragments_index, mobi_exists_frag_indx)
|
683
|
+
DEFINE_PREDICATE(has_guide_index, mobi_exists_guide_indx)
|
684
|
+
DEFINE_PREDICATE(has_ncx_index, mobi_exists_ncx)
|
685
|
+
DEFINE_PREDICATE(has_orth_index, mobi_exists_orth)
|
686
|
+
DEFINE_PREDICATE(has_infl_index, mobi_exists_infl)
|
687
|
+
DEFINE_PREDICATE(is_hybrid, mobi_is_hybrid)
|
688
|
+
DEFINE_PREDICATE(is_encrypted, mobi_is_encrypted)
|
689
|
+
DEFINE_PREDICATE(is_mobipocket, mobi_is_mobipocket)
|
690
|
+
DEFINE_PREDICATE(is_dictionary, mobi_is_dictionary)
|
691
|
+
DEFINE_PREDICATE(is_kf8, mobi_is_kf8)
|
692
|
+
|
693
|
+
static VALUE mb_book_records(VALUE self)
|
694
|
+
{
|
695
|
+
mb_BOOK *book = DATA_PTR(self);
|
696
|
+
VALUE res;
|
697
|
+
const MOBIPdbRecord *rec;
|
698
|
+
|
699
|
+
if (book == NULL || book->data == NULL) {
|
700
|
+
mb_raise(MOBI_INIT_FAILED, "the MOBI data is not loaded");
|
701
|
+
}
|
702
|
+
rec = book->data->rec;
|
703
|
+
if (rec == NULL) {
|
704
|
+
return Qnil;
|
705
|
+
}
|
706
|
+
|
707
|
+
res = rb_ary_new();
|
708
|
+
while (rec != NULL) {
|
709
|
+
VALUE item = rb_hash_new();
|
710
|
+
rb_hash_aset(item, ID2SYM(rb_intern("offset")), INT2FIX(rec->offset));
|
711
|
+
rb_hash_aset(item, ID2SYM(rb_intern("size")), INT2FIX(rec->size));
|
712
|
+
rb_hash_aset(item, ID2SYM(rb_intern("attributes")), INT2FIX(rec->attributes));
|
713
|
+
rb_hash_aset(item, ID2SYM(rb_intern("uid")), INT2FIX(rec->uid));
|
714
|
+
rb_hash_aset(item, ID2SYM(rb_intern("data")), rb_str_new((const char *)rec->data, rec->size));
|
715
|
+
rb_ary_push(res, item);
|
716
|
+
rec = rec->next;
|
717
|
+
}
|
718
|
+
return res;
|
719
|
+
}
|
720
|
+
|
721
|
+
static VALUE mb_book_rawml(VALUE self)
|
722
|
+
{
|
723
|
+
mb_BOOK *book = DATA_PTR(self);
|
724
|
+
MOBI_RET rc;
|
725
|
+
char *text = NULL;
|
726
|
+
size_t size;
|
727
|
+
VALUE res;
|
728
|
+
|
729
|
+
if (book == NULL || book->data == NULL) {
|
730
|
+
mb_raise(MOBI_INIT_FAILED, "the MOBI data is not loaded");
|
731
|
+
}
|
732
|
+
size = mobi_get_text_maxsize(book->data);
|
733
|
+
if (size == MOBI_NOTSET) {
|
734
|
+
mb_raise(MOBI_DATA_CORRUPT, "unable to determine size for rawml");
|
735
|
+
}
|
736
|
+
text = calloc(size + 1, sizeof(char));
|
737
|
+
if (text == NULL) {
|
738
|
+
mb_raise(MOBI_MALLOC_FAILED, "unable to allocate memory for rawml buffer");
|
739
|
+
}
|
740
|
+
rc = mobi_get_rawml(book->data, text, &size);
|
741
|
+
if (rc != MOBI_SUCCESS) {
|
742
|
+
free(text);
|
743
|
+
mb_raise(rc, "unable to generate rawml");
|
744
|
+
return Qnil;
|
745
|
+
}
|
746
|
+
res = rb_str_new(text, size);
|
747
|
+
free(text);
|
748
|
+
return res;
|
749
|
+
}
|
750
|
+
|
751
|
+
static VALUE mb_extract_mobiparts(const MOBIPart *part)
|
752
|
+
{
|
753
|
+
VALUE items = rb_ary_new();
|
754
|
+
while (part != NULL) {
|
755
|
+
VALUE item = rb_hash_new();
|
756
|
+
rb_hash_aset(item, ID2SYM(rb_intern("type")), INT2FIX(part->type));
|
757
|
+
switch (part->type) {
|
758
|
+
case T_UNKNOWN:
|
759
|
+
rb_hash_aset(item, ID2SYM(rb_intern("type_sym")), ID2SYM(rb_intern("unknown")));
|
760
|
+
break;
|
761
|
+
case T_HTML:
|
762
|
+
rb_hash_aset(item, ID2SYM(rb_intern("type_sym")), ID2SYM(rb_intern("html")));
|
763
|
+
break;
|
764
|
+
case T_CSS:
|
765
|
+
rb_hash_aset(item, ID2SYM(rb_intern("type_sym")), ID2SYM(rb_intern("css")));
|
766
|
+
break;
|
767
|
+
case T_SVG:
|
768
|
+
rb_hash_aset(item, ID2SYM(rb_intern("type_sym")), ID2SYM(rb_intern("svg")));
|
769
|
+
break;
|
770
|
+
case T_OPF:
|
771
|
+
rb_hash_aset(item, ID2SYM(rb_intern("type_sym")), ID2SYM(rb_intern("opf")));
|
772
|
+
break;
|
773
|
+
case T_NCX:
|
774
|
+
rb_hash_aset(item, ID2SYM(rb_intern("type_sym")), ID2SYM(rb_intern("ncx")));
|
775
|
+
break;
|
776
|
+
case T_JPG:
|
777
|
+
rb_hash_aset(item, ID2SYM(rb_intern("type_sym")), ID2SYM(rb_intern("jpg")));
|
778
|
+
break;
|
779
|
+
case T_GIF:
|
780
|
+
rb_hash_aset(item, ID2SYM(rb_intern("type_sym")), ID2SYM(rb_intern("gif")));
|
781
|
+
break;
|
782
|
+
case T_PNG:
|
783
|
+
rb_hash_aset(item, ID2SYM(rb_intern("type_sym")), ID2SYM(rb_intern("png")));
|
784
|
+
break;
|
785
|
+
case T_BMP:
|
786
|
+
rb_hash_aset(item, ID2SYM(rb_intern("type_sym")), ID2SYM(rb_intern("bmp")));
|
787
|
+
break;
|
788
|
+
case T_OTF:
|
789
|
+
rb_hash_aset(item, ID2SYM(rb_intern("type_sym")), ID2SYM(rb_intern("otf")));
|
790
|
+
break;
|
791
|
+
case T_TTF:
|
792
|
+
rb_hash_aset(item, ID2SYM(rb_intern("type_sym")), ID2SYM(rb_intern("ttf")));
|
793
|
+
break;
|
794
|
+
case T_MP3:
|
795
|
+
rb_hash_aset(item, ID2SYM(rb_intern("type_sym")), ID2SYM(rb_intern("mp3")));
|
796
|
+
break;
|
797
|
+
case T_MPG:
|
798
|
+
rb_hash_aset(item, ID2SYM(rb_intern("type_sym")), ID2SYM(rb_intern("mpg")));
|
799
|
+
break;
|
800
|
+
case T_PDF:
|
801
|
+
rb_hash_aset(item, ID2SYM(rb_intern("type_sym")), ID2SYM(rb_intern("pdf")));
|
802
|
+
break;
|
803
|
+
case T_FONT:
|
804
|
+
rb_hash_aset(item, ID2SYM(rb_intern("type_sym")), ID2SYM(rb_intern("font")));
|
805
|
+
break;
|
806
|
+
case T_AUDIO:
|
807
|
+
rb_hash_aset(item, ID2SYM(rb_intern("type_sym")), ID2SYM(rb_intern("audio")));
|
808
|
+
break;
|
809
|
+
case T_VIDEO:
|
810
|
+
rb_hash_aset(item, ID2SYM(rb_intern("type_sym")), ID2SYM(rb_intern("video")));
|
811
|
+
break;
|
812
|
+
case T_BREAK:
|
813
|
+
rb_hash_aset(item, ID2SYM(rb_intern("type_sym")), ID2SYM(rb_intern("break")));
|
814
|
+
break;
|
815
|
+
}
|
816
|
+
rb_hash_aset(item, ID2SYM(rb_intern("uid")), INT2FIX(part->uid));
|
817
|
+
rb_hash_aset(item, ID2SYM(rb_intern("size")), INT2FIX(part->size));
|
818
|
+
rb_hash_aset(item, ID2SYM(rb_intern("data")), rb_str_new((const char *)part->data, part->size));
|
819
|
+
part = part->next;
|
820
|
+
rb_ary_push(items, item);
|
821
|
+
}
|
822
|
+
return items;
|
823
|
+
}
|
824
|
+
|
825
|
+
static VALUE mb_book_rawml_parts(VALUE self)
|
826
|
+
{
|
827
|
+
mb_BOOK *book = DATA_PTR(self);
|
828
|
+
MOBI_RET rc;
|
829
|
+
MOBIRawml *rawml;
|
830
|
+
VALUE res;
|
831
|
+
|
832
|
+
if (book == NULL || book->data == NULL) {
|
833
|
+
mb_raise(MOBI_INIT_FAILED, "the MOBI data is not loaded");
|
834
|
+
}
|
835
|
+
rawml = mobi_init_rawml(book->data);
|
836
|
+
if (rawml == NULL) {
|
837
|
+
mb_raise(MOBI_MALLOC_FAILED, "unable to allocate memory for rawml structure");
|
838
|
+
}
|
839
|
+
rc = mobi_parse_rawml(rawml, book->data);
|
840
|
+
if (rc != MOBI_SUCCESS) {
|
841
|
+
mobi_free_rawml(rawml);
|
842
|
+
mb_raise(rc, "unable to generate rawml");
|
843
|
+
return Qnil;
|
844
|
+
}
|
845
|
+
res = rb_hash_new();
|
846
|
+
rb_hash_aset(res, ID2SYM(rb_intern("version")), INT2FIX(rawml->version));
|
847
|
+
if (rawml->markup != NULL) {
|
848
|
+
rb_hash_aset(res, ID2SYM(rb_intern("markup")), mb_extract_mobiparts(rawml->markup));
|
849
|
+
}
|
850
|
+
if (rawml->flow != NULL) {
|
851
|
+
rb_hash_aset(res, ID2SYM(rb_intern("flow")), mb_extract_mobiparts(rawml->flow));
|
852
|
+
}
|
853
|
+
if (rawml->resources != NULL) {
|
854
|
+
rb_hash_aset(res, ID2SYM(rb_intern("resources")), mb_extract_mobiparts(rawml->resources));
|
855
|
+
}
|
856
|
+
mobi_free_rawml(rawml);
|
857
|
+
return res;
|
858
|
+
}
|
859
|
+
|
860
|
+
static void init_mobi_book()
|
861
|
+
{
|
862
|
+
mb_cBook = rb_define_class_under(mb_mMOBI, "Book", rb_cObject);
|
863
|
+
rb_define_alloc_func(mb_cBook, mb_book_alloc);
|
864
|
+
rb_define_method(mb_cBook, "initialize", mb_book_init, 1);
|
865
|
+
rb_define_method(mb_cBook, "next", mb_book_next, 0);
|
866
|
+
rb_define_method(mb_cBook, "mobi_header", mb_book_mobi_header, 0);
|
867
|
+
rb_define_method(mb_cBook, "pdb_header", mb_book_pdb_header, 0);
|
868
|
+
rb_define_method(mb_cBook, "record0_header", mb_book_record0_header, 0);
|
869
|
+
rb_define_method(mb_cBook, "exth_header", mb_book_exth_header, 0);
|
870
|
+
rb_define_method(mb_cBook, "full_name", mb_book_full_name, 0);
|
871
|
+
rb_define_method(mb_cBook, "title", mb_book_title, 0);
|
872
|
+
rb_define_method(mb_cBook, "author", mb_book_author, 0);
|
873
|
+
rb_define_method(mb_cBook, "publisher", mb_book_publisher, 0);
|
874
|
+
rb_define_method(mb_cBook, "imprint", mb_book_imprint, 0);
|
875
|
+
rb_define_method(mb_cBook, "description", mb_book_description, 0);
|
876
|
+
rb_define_method(mb_cBook, "isbn", mb_book_isbn, 0);
|
877
|
+
rb_define_method(mb_cBook, "subject", mb_book_subject, 0);
|
878
|
+
rb_define_method(mb_cBook, "publishdate", mb_book_publishdate, 0);
|
879
|
+
rb_define_method(mb_cBook, "review", mb_book_review, 0);
|
880
|
+
rb_define_method(mb_cBook, "contributor", mb_book_contributor, 0);
|
881
|
+
rb_define_method(mb_cBook, "copyright", mb_book_copyright, 0);
|
882
|
+
rb_define_method(mb_cBook, "asin", mb_book_asin, 0);
|
883
|
+
rb_define_method(mb_cBook, "language", mb_book_language, 0);
|
884
|
+
rb_define_method(mb_cBook, "has_mobi_header?", mb_book_p_has_mobi_header, 0);
|
885
|
+
rb_define_method(mb_cBook, "has_fdst?", mb_book_p_has_fdst, 0);
|
886
|
+
rb_define_method(mb_cBook, "has_skeleton_index?", mb_book_p_has_skeleton_index, 0);
|
887
|
+
rb_define_method(mb_cBook, "has_fragments_index?", mb_book_p_has_fragments_index, 0);
|
888
|
+
rb_define_method(mb_cBook, "has_guide_index?", mb_book_p_has_guide_index, 0);
|
889
|
+
rb_define_method(mb_cBook, "has_ncx_index?", mb_book_p_has_ncx_index, 0);
|
890
|
+
rb_define_method(mb_cBook, "has_orth_index?", mb_book_p_has_orth_index, 0);
|
891
|
+
rb_define_method(mb_cBook, "has_infl_index?", mb_book_p_has_infl_index, 0);
|
892
|
+
rb_define_method(mb_cBook, "is_hybrid?", mb_book_p_is_hybrid, 0);
|
893
|
+
rb_define_method(mb_cBook, "is_encrypted?", mb_book_p_is_encrypted, 0);
|
894
|
+
rb_define_method(mb_cBook, "is_mobipocket?", mb_book_p_is_mobipocket, 0);
|
895
|
+
rb_define_method(mb_cBook, "is_dictionary?", mb_book_p_is_dictionary, 0);
|
896
|
+
rb_define_method(mb_cBook, "is_kf8?", mb_book_p_is_kf8, 0);
|
897
|
+
rb_define_method(mb_cBook, "records", mb_book_records, 0);
|
898
|
+
rb_define_method(mb_cBook, "rawml", mb_book_rawml, 0);
|
899
|
+
rb_define_method(mb_cBook, "rawml_parts", mb_book_rawml_parts, 0);
|
900
|
+
}
|
901
|
+
|
902
|
+
void Init_mobi_ext()
|
903
|
+
{
|
904
|
+
mb_mMOBI = rb_define_module("MOBI");
|
905
|
+
rb_define_const(mb_mMOBI, "LIB_VERSION", rb_str_freeze(rb_external_str_new_cstr(mobi_version())));
|
906
|
+
mb_eError = rb_const_get(mb_mMOBI, rb_intern("Error"));
|
907
|
+
|
908
|
+
init_mobi_book();
|
909
|
+
}
|