diff options
Diffstat (limited to 'src/gempub.c')
-rw-r--r-- | src/gempub.c | 88 |
1 files changed, 84 insertions, 4 deletions
diff --git a/src/gempub.c b/src/gempub.c index c9b1c242..0f0345dc 100644 --- a/src/gempub.c +++ b/src/gempub.c | |||
@@ -25,31 +25,96 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |||
25 | #include "lang.h" | 25 | #include "lang.h" |
26 | #include "defs.h" | 26 | #include "defs.h" |
27 | #include "gmdocument.h" | 27 | #include "gmdocument.h" |
28 | #include "gmrequest.h" | ||
28 | #include "ui/util.h" | 29 | #include "ui/util.h" |
30 | #include "app.h" | ||
29 | 31 | ||
30 | #include <the_Foundation/archive.h> | 32 | #include <the_Foundation/archive.h> |
31 | #include <the_Foundation/file.h> | 33 | #include <the_Foundation/file.h> |
32 | #include <the_Foundation/path.h> | 34 | #include <the_Foundation/path.h> |
35 | #include <the_Foundation/regexp.h> | ||
33 | 36 | ||
34 | const char *mimeType_Gempub = "application/gpub+zip"; | 37 | const char *mimeType_Gempub = "application/gpub+zip"; |
35 | 38 | ||
39 | /*----------------------------------------------------------------------------------------------*/ | ||
40 | |||
41 | iDeclareType(GempubNavLink) | ||
42 | |||
43 | struct Impl_GempubNavLink { | ||
44 | iString url; | ||
45 | iString label; | ||
46 | }; | ||
47 | |||
48 | static void init_GempubNavLink(iGempubNavLink *d) { | ||
49 | init_String(&d->url); | ||
50 | init_String(&d->label); | ||
51 | } | ||
52 | |||
53 | static void deinit_GempubNavLink(iGempubNavLink *d) { | ||
54 | deinit_String(&d->url); | ||
55 | deinit_String(&d->label); | ||
56 | } | ||
57 | |||
58 | iDefineTypeConstruction(GempubNavLink) | ||
59 | |||
60 | /*----------------------------------------------------------------------------------------------*/ | ||
61 | |||
36 | struct Impl_Gempub { | 62 | struct Impl_Gempub { |
37 | iArchive *arch; | 63 | iArchive *arch; |
38 | iString baseUrl; | 64 | iString baseUrl; |
39 | iString props[max_GempubProperty]; | 65 | iString props[max_GempubProperty]; |
66 | iArray *navLinks; /* from index page */ | ||
40 | }; | 67 | }; |
41 | 68 | ||
42 | iDefineTypeConstruction(Gempub) | 69 | iDefineTypeConstruction(Gempub) |
43 | 70 | ||
71 | static void parseNavigationLinks_Gempub_(const iGempub *d) { | ||
72 | if (!isEmpty_Array(d->navLinks)) { | ||
73 | return; | ||
74 | } | ||
75 | iGmRequest *index = iClob(new_GmRequest(certs_App())); | ||
76 | setUrl_GmRequest(index, indexPageUrl_Gempub(d)); | ||
77 | submit_GmRequest(index); /* this is just a local file read */ | ||
78 | iAssert(isFinished_GmRequest(index)); | ||
79 | iRangecc src = iNullRange; | ||
80 | iRegExp *linkPattern = iClob(newGemtextLink_RegExp()); | ||
81 | while (nextSplit_Rangecc(range_Block(body_GmRequest(index)), "\n", &src)) { | ||
82 | iRangecc line = src; | ||
83 | trim_Rangecc(&line); | ||
84 | iRegExpMatch m; | ||
85 | init_RegExpMatch(&m); | ||
86 | if (matchRange_RegExp(linkPattern, line, &m)) { | ||
87 | iBeginCollect(); | ||
88 | const iRangecc url = capturedRange_RegExpMatch(&m, 1); | ||
89 | iUrl parts; | ||
90 | init_Url(&parts, collectNewRange_String(url)); | ||
91 | if (isEmpty_Range(&parts.scheme)) { | ||
92 | iGempubNavLink link; | ||
93 | init_GempubNavLink(&link); | ||
94 | set_String(&link.url, absoluteUrl_String(url_GmRequest(index), collectNewRange_String(url))); | ||
95 | setRange_String(&link.label, capturedRange_RegExpMatch(&m, 2)); | ||
96 | trim_String(&link.label); | ||
97 | pushBack_Array(d->navLinks, &link); | ||
98 | } | ||
99 | iEndCollect(); | ||
100 | } | ||
101 | } | ||
102 | } | ||
103 | |||
44 | void init_Gempub(iGempub *d) { | 104 | void init_Gempub(iGempub *d) { |
45 | d->arch = NULL; | 105 | d->arch = NULL; |
46 | init_String(&d->baseUrl); | 106 | init_String(&d->baseUrl); |
47 | iForIndices(i, d->props) { | 107 | iForIndices(i, d->props) { |
48 | init_String(&d->props[i]); | 108 | init_String(&d->props[i]); |
49 | } | 109 | } |
110 | d->navLinks = new_Array(sizeof(iGempubNavLink)); | ||
50 | } | 111 | } |
51 | 112 | ||
52 | void deinit_Gempub(iGempub *d) { | 113 | void deinit_Gempub(iGempub *d) { |
114 | iForEach(Array, n, d->navLinks) { | ||
115 | deinit_GempubNavLink(n.value); | ||
116 | } | ||
117 | delete_Array(d->navLinks); | ||
53 | iForIndices(i, d->props) { | 118 | iForIndices(i, d->props) { |
54 | deinit_String(&d->props[i]); | 119 | deinit_String(&d->props[i]); |
55 | } | 120 | } |
@@ -140,12 +205,27 @@ void close_Gempub(iGempub *d) { | |||
140 | } | 205 | } |
141 | } | 206 | } |
142 | 207 | ||
208 | void setBaseUrl_Gempub(iGempub *d, const iString *url) { | ||
209 | set_String(&d->baseUrl, url); | ||
210 | } | ||
211 | |||
143 | iBool isOpen_Gempub(const iGempub *d) { | 212 | iBool isOpen_Gempub(const iGempub *d) { |
144 | return d->arch != NULL; | 213 | return d->arch != NULL; |
145 | } | 214 | } |
146 | 215 | ||
147 | void setBaseUrl_Gempub(iGempub *d, const iString *url) { | 216 | const iString *indexPageUrl_Gempub(const iGempub *d) { |
148 | set_String(&d->baseUrl, url); | 217 | iAssert(!isEmpty_String(&d->baseUrl)); |
218 | iString *dir = collect_String(copy_String(&d->baseUrl)); | ||
219 | appendCStr_String(dir, "/"); | ||
220 | return absoluteUrl_String(dir, &d->props[index_GempubProperty]); | ||
221 | } | ||
222 | |||
223 | const iString *navStartLinkUrl_Gempub(const iGempub *d) { | ||
224 | parseNavigationLinks_Gempub_(d); | ||
225 | if (isEmpty_Array(d->navLinks)) { | ||
226 | return NULL; /* has no navigation structure */ | ||
227 | } | ||
228 | return &((const iGempubNavLink *) constFront_Array(d->navLinks))->url; | ||
149 | } | 229 | } |
150 | 230 | ||
151 | static iBool hasProperty_Gempub_(const iGempub *d, enum iGempubProperty prop) { | 231 | static iBool hasProperty_Gempub_(const iGempub *d, enum iGempubProperty prop) { |
@@ -176,7 +256,7 @@ iString *coverPageSource_Gempub(const iGempub *d) { | |||
176 | appendProperty_Gempub_(d, "${gempub.meta.author}:", author_GempubProperty, out); | 256 | appendProperty_Gempub_(d, "${gempub.meta.author}:", author_GempubProperty, out); |
177 | if (!isRemote_Gempub_(d)) { | 257 | if (!isRemote_Gempub_(d)) { |
178 | appendFormat_String(out, "\n=> %s " book_Icon " ${gempub.cover.view}\n", | 258 | appendFormat_String(out, "\n=> %s " book_Icon " ${gempub.cover.view}\n", |
179 | cstrCollect_String(concat_Path(baseUrl, &d->props[index_GempubProperty]))); | 259 | cstr_String(indexPageUrl_Gempub(d))); |
180 | if (hasProperty_Gempub_(d, cover_GempubProperty)) { | 260 | if (hasProperty_Gempub_(d, cover_GempubProperty)) { |
181 | appendFormat_String(out, "\n=> %s ${gempub.cover.image}\n", | 261 | appendFormat_String(out, "\n=> %s ${gempub.cover.image}\n", |
182 | cstrCollect_String(concat_Path(baseUrl, &d->props[cover_GempubProperty]))); | 262 | cstrCollect_String(concat_Path(baseUrl, &d->props[cover_GempubProperty]))); |