summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/gempub.c84
-rw-r--r--src/gempub.h4
2 files changed, 83 insertions, 5 deletions
diff --git a/src/gempub.c b/src/gempub.c
index c9b1c242..e1f246ac 100644
--- a/src/gempub.c
+++ b/src/gempub.c
@@ -25,31 +25,92 @@ 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
34const char *mimeType_Gempub = "application/gpub+zip"; 37const char *mimeType_Gempub = "application/gpub+zip";
35 38
39/*----------------------------------------------------------------------------------------------*/
40
41iDeclareType(GempubNavLink)
42
43struct Impl_GempubNavLink {
44 iString url;
45 iString label;
46};
47
48static void init_GempubNavLink(iGempubNavLink *d) {
49 init_String(&d->url);
50 init_String(&d->label);
51}
52
53static void deinit_GempubNavLink(iGempubNavLink *d) {
54 deinit_String(&d->url);
55 deinit_String(&d->label);
56}
57
58iDefineTypeConstruction(GempubNavLink)
59
60/*----------------------------------------------------------------------------------------------*/
61
36struct Impl_Gempub { 62struct 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
42iDefineTypeConstruction(Gempub) 69iDefineTypeConstruction(Gempub)
43 70
71static 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 iGempubNavLink link;
89 init_GempubNavLink(&link);
90 const iRangecc url = capturedRange_RegExpMatch(&m, 1);
91 set_String(&link.url, absoluteUrl_String(url_GmRequest(index), collectNewRange_String(url)));
92 setRange_String(&link.label, capturedRange_RegExpMatch(&m, 2));
93 trim_String(&link.label);
94 pushBack_Array(d->navLinks, &link);
95 iEndCollect();
96 }
97 }
98}
99
44void init_Gempub(iGempub *d) { 100void init_Gempub(iGempub *d) {
45 d->arch = NULL; 101 d->arch = NULL;
46 init_String(&d->baseUrl); 102 init_String(&d->baseUrl);
47 iForIndices(i, d->props) { 103 iForIndices(i, d->props) {
48 init_String(&d->props[i]); 104 init_String(&d->props[i]);
49 } 105 }
106 d->navLinks = new_Array(sizeof(iGempubNavLink));
50} 107}
51 108
52void deinit_Gempub(iGempub *d) { 109void deinit_Gempub(iGempub *d) {
110 iForEach(Array, n, d->navLinks) {
111 deinit_GempubNavLink(n.value);
112 }
113 delete_Array(d->navLinks);
53 iForIndices(i, d->props) { 114 iForIndices(i, d->props) {
54 deinit_String(&d->props[i]); 115 deinit_String(&d->props[i]);
55 } 116 }
@@ -140,12 +201,27 @@ void close_Gempub(iGempub *d) {
140 } 201 }
141} 202}
142 203
204void setBaseUrl_Gempub(iGempub *d, const iString *url) {
205 set_String(&d->baseUrl, url);
206}
207
143iBool isOpen_Gempub(const iGempub *d) { 208iBool isOpen_Gempub(const iGempub *d) {
144 return d->arch != NULL; 209 return d->arch != NULL;
145} 210}
146 211
147void setBaseUrl_Gempub(iGempub *d, const iString *url) { 212const iString *indexPageUrl_Gempub(const iGempub *d) {
148 set_String(&d->baseUrl, url); 213 iAssert(!isEmpty_String(&d->baseUrl));
214 iString *dir = collect_String(copy_String(&d->baseUrl));
215 appendCStr_String(dir, "/");
216 return absoluteUrl_String(dir, &d->props[index_GempubProperty]);
217}
218
219const iString *navStartLinkUrl_Gempub(const iGempub *d) {
220 parseNavigationLinks_Gempub_(d);
221 if (isEmpty_Array(d->navLinks)) {
222 return NULL; /* has no navigation structure */
223 }
224 return &((const iGempubNavLink *) constFront_Array(d->navLinks))->url;
149} 225}
150 226
151static iBool hasProperty_Gempub_(const iGempub *d, enum iGempubProperty prop) { 227static iBool hasProperty_Gempub_(const iGempub *d, enum iGempubProperty prop) {
@@ -176,7 +252,7 @@ iString *coverPageSource_Gempub(const iGempub *d) {
176 appendProperty_Gempub_(d, "${gempub.meta.author}:", author_GempubProperty, out); 252 appendProperty_Gempub_(d, "${gempub.meta.author}:", author_GempubProperty, out);
177 if (!isRemote_Gempub_(d)) { 253 if (!isRemote_Gempub_(d)) {
178 appendFormat_String(out, "\n=> %s " book_Icon " ${gempub.cover.view}\n", 254 appendFormat_String(out, "\n=> %s " book_Icon " ${gempub.cover.view}\n",
179 cstrCollect_String(concat_Path(baseUrl, &d->props[index_GempubProperty]))); 255 cstr_String(indexPageUrl_Gempub(d)));
180 if (hasProperty_Gempub_(d, cover_GempubProperty)) { 256 if (hasProperty_Gempub_(d, cover_GempubProperty)) {
181 appendFormat_String(out, "\n=> %s ${gempub.cover.image}\n", 257 appendFormat_String(out, "\n=> %s ${gempub.cover.image}\n",
182 cstrCollect_String(concat_Path(baseUrl, &d->props[cover_GempubProperty]))); 258 cstrCollect_String(concat_Path(baseUrl, &d->props[cover_GempubProperty])));
diff --git a/src/gempub.h b/src/gempub.h
index 6c1103de..fb3c510b 100644
--- a/src/gempub.h
+++ b/src/gempub.h
@@ -56,6 +56,8 @@ iBool isOpen_Gempub (const iGempub *);
56iString * coverPageSource_Gempub (const iGempub *); 56iString * coverPageSource_Gempub (const iGempub *);
57iBool preloadCoverImage_Gempub(const iGempub *, iGmDocument *doc); 57iBool preloadCoverImage_Gempub(const iGempub *, iGmDocument *doc);
58 58
59const iString *property_Gempub (const iGempub *, enum iGempubProperty); 59const iString * property_Gempub (const iGempub *, enum iGempubProperty);
60const iString * indexPageUrl_Gempub (const iGempub *);
61const iString * navStartLinkUrl_Gempub (const iGempub *); /* for convenience */
60 62
61extern const char *mimeType_Gempub; 63extern const char *mimeType_Gempub;