nyctergatis.com

Contact

Projects
Sysquake Remote Live
NME
PDF
Hike
Sudoku
GifBuilder
jpeglib for Palm OS
MySQL Client
Cross-GCC for Mac OS
NE.c
Go to the documentation of this file.
00001 
00008 /* License: new BSD license (see NE.h) */
00009 
00010 #include <stdlib.h>
00011 #include <stdio.h>
00012 #include <string.h>
00013 #include "zip.h"
00014 #include "NE.h"
00015 
00016 #if defined(_WIN32) || defined(_WIN64)
00017 
00018 #   define strncasecmp _strnicmp
00019 #endif
00020 
00021 #define kBufferSize 65536L  // a larger value might be marginally more efficient
00022 #define kPathSize 512   // must be large enough for document paths
00023 
00024 #define DOCDIR "OPS"
00025 #define ROOTDOC "content.opf"
00026 #define NCXDOC "toc.ncx"
00027 #define COVERDOC "cover.xhtml"
00028 #define ENDNOTESDOC "endnotes.xhtml"
00029 
00030 #define Chk(e) do { err = (e); if (err != kNEErrOk) return err; } while (0)
00031 
00032 // string utility functions
00033 
00034 NEErr NEStringCopy(char **str, char const *src, int srcLen)
00035 {
00036     int i;
00037     
00038     if (*str)
00039         free(*str);
00040     
00041     if (srcLen < 0)
00042         srcLen = strlen(src);
00043     
00044     *str = malloc(srcLen + 1);
00045     if (!*str)
00046         return kNEErrMalloc;
00047     
00048     for (i = 0; i < srcLen; i++)
00049         (*str)[i] = src[i];
00050     (*str)[i] = '\0';
00051     
00052     return kNEErrOk;
00053 }
00054 
00055 NEErr NEStringCat(char **str, char const *src, int srcLen)
00056 {
00057     if (!*str)
00058         return NEStringCopy(str, src, srcLen);
00059     else
00060     {
00061         int i;
00062         int strLen = strlen(*str);
00063         if (srcLen < 0)
00064             srcLen = strlen(src);
00065         
00066         *str = realloc(*str, strLen + srcLen + 1);
00067         if (!*str)
00068             return kNEErrMalloc;
00069         
00070         for (i = 0; i < srcLen; i++)
00071             (*str)[strLen + i] = src[i];
00072         (*str)[strLen + i] = '\0';
00073         return kNEErrOk;
00074     }
00075 }
00076 
00077 NEErr NEStringAdd(char **str, char const *src, int srcLen)
00078 {
00079     if (!*str)
00080         return NEStringCopy(str, src, srcLen);
00081     else
00082     {
00083         int i;
00084         int strLen = strlen(*str);
00085         if (srcLen < 0)
00086             srcLen = strlen(src);
00087         
00088         *str = realloc(*str, strLen + srcLen + 2);
00089         if (!*str)
00090             return kNEErrMalloc;
00091         
00092         (*str)[strLen] = '\n';
00093         for (i = 0; i < srcLen; i++)
00094             (*str)[strLen + 1 + i] = src[i];
00095         (*str)[strLen + 1 + i] = '\0';
00096         return kNEErrOk;
00097     }
00098 }
00099 
00100 char const *NEStringNextPart(char const *str)
00101 {
00102     if (!str)
00103         return NULL;
00104     while (str[0] && str[0] != '\n')
00105         str++;
00106     if (str[0])
00107         return str + 1;
00108     else
00109         return NULL;
00110 }
00111 
00112 int NEStringPartLength(char const *str)
00113 {
00114     int n;
00115     for (n = 0; str[n] && str[n] != '\n'; n++)
00116         ;
00117     return n;
00118 }
00119 
00120 NEBoolean NEStringEq(char const *str, char const *str2, int len2)
00121 {
00122     int i;
00123     if (len2 >= 0)
00124     {
00125         for (i = 0; i < len2; i++)
00126             if (str[i] != str2[i])
00127                 return FALSE;
00128     }
00129     else
00130         for (i = 0; str2[i] && str2[i] != '\n'; i++)
00131             if (str[i] != str2[i])
00132                 return FALSE;
00133     return str[i] == '\0' || str[i] == '\n';
00134 }
00135 
00136 void NEStringFree(char **str)
00137 {
00138     if (*str)
00139         free(*str);
00140     *str = NULL;
00141 }
00142 
00143 NEErr NEBegin(NEPtr ne, char const *filename)
00144 {
00145     int zerr;
00146     static char const mimetype[] = "application/epub+zip\n";
00147     
00148     if (filename)
00149     {
00150         ne->zf = zipOpen64(filename, APPEND_STATUS_CREATE);
00151         if (!ne->zf)
00152             return kNEErrCannotCreateEPUBFile;
00153     }
00154     else
00155         ne->zf = NULL;
00156     
00157     // initialize meta information
00158     ne->title = NULL;
00159     NEStringCopy(&ne->title, "Untitled", -1);
00160     ne->creator = NULL;
00161     ne->identifier = NULL;
00162     NEStringCopy(&ne->identifier, "no-identifier", -1);
00163     ne->language = NULL;
00164     ne->subject = NULL;
00165     ne->description = NULL;
00166     ne->publisher = NULL;
00167     ne->date = NULL;
00168     ne->source = NULL;
00169     ne->rights = NULL;
00170     
00171     // initialize parts and other documents
00172     ne->parts = NULL;
00173     ne->auxParts = NULL;
00174     ne->cover = NULL;
00175     ne->other = NULL;
00176     ne->coverImage = NULL;
00177     
00178     // initialize other fields
00179     ne->tocEntries = NULL;
00180     ne->ncxCount = 0;
00181     ne->maxTOCDepth = 1;
00182     ne->endnotes = NULL;
00183     ne->endnoteCount = 0;
00184     ne->lastRefLink = NULL;
00185     ne->currentDoc = NULL;
00186     
00187     // add file "mimetype" (first file, uncompressed)
00188     zerr = zipOpenNewFileInZip(ne->zf,
00189             "mimetype", NULL,
00190             NULL, 0, NULL, 0,
00191             NULL,
00192             0, 0);
00193     if (zerr != Z_OK)
00194         return kNEErrZip;
00195     zerr = zipWriteInFileInZip(ne->zf, mimetype, strlen(mimetype));
00196     if (zerr != Z_OK)
00197         return kNEErrZip;
00198     zerr = zipCloseFileInZip(ne->zf);
00199     if (zerr != Z_OK)
00200         return kNEErrZip;
00201     
00202     return kNEErrOk;
00203 }
00204 
00205 NEErr NEAddMetadata(NEPtr ne,
00206     NEMetadataKey key, char const *data, int dataLen)
00207 {
00208     switch (key)
00209     {
00210         case kNEMetaTitle:
00211             NEStringCopy(&ne->title, data, dataLen);
00212             break;
00213         case kNEMetaCreator:
00214             NEStringAdd(&ne->creator, data, dataLen);
00215             break;
00216         case kNEMetaIdentifier:
00217             NEStringCopy(&ne->identifier, data, dataLen);
00218             break;
00219         case kNEMetaLanguage:
00220             NEStringAdd(&ne->language, data, dataLen);
00221             break;
00222         case kNEMetaSubject:
00223             NEStringAdd(&ne->subject, data, dataLen);
00224             break;
00225         case kNEMetaDescription:
00226             NEStringCopy(&ne->description, data, dataLen);
00227             break;
00228         case kNEMetaPublisher:
00229             NEStringCopy(&ne->publisher, data, dataLen);
00230             break;
00231         case kNEMetaDate:
00232             NEStringCopy(&ne->date, data, dataLen);
00233             break;
00234         case kNEMetaSource:
00235             NEStringCopy(&ne->source, data, dataLen);
00236             break;
00237         case kNEMetaRights:
00238             NEStringCopy(&ne->rights, data, dataLen);
00239             break;
00240     }
00241     return kNEErrOk;
00242 }
00243 
00244 NEErr NESetCoverImage(NEPtr ne, char const *filename, int filenameLen)
00245 {
00246     NEErr err;
00247     //Chk(NEStringAdd(&ne->auxParts, filename, filenameLen));
00248     Chk(NEStringCopy(&ne->coverImage, filename, filenameLen));
00249     Chk(NEAddFile(ne, ne->coverImage, ne->coverImage));
00250     return kNEErrOk;
00251 }
00252 
00253 NEErr NEAddPart(NEPtr ne, char const *filename, NEBoolean auxiliary)
00254 {
00255     NEErr err;
00256     
00257     if (auxiliary)
00258         Chk(NEStringAdd(&ne->auxParts, filename, -1));
00259     else
00260         Chk(NEStringAdd(&ne->parts, filename, -1));
00261     return kNEErrOk;
00262 }
00263 
00264 static char const *SuffixToMimetype(char const *filename, int filenameLen)
00265 {
00266     int i, suffix;
00267     static struct
00268     {
00269         char const *suffix;
00270         char const *mimetype;
00271     } const m[] = {
00272         {"gif", "image/gif"},
00273         {"jpg", "image/jpeg"},
00274         {"png", "image/png"},
00275         {"svg", "image/svg+xml"},
00276         {"xhtml", "text/xhtml+xml"},
00277         {"css", "text/css"},
00278         {"xml", "application/xml"},
00279         {"ncx", "application/x-dtbncx+xml"},
00280         {NULL, NULL}
00281     };
00282     
00283     if (filenameLen < 0)
00284         filenameLen = strlen(filename);
00285     for (suffix = filenameLen; suffix > 0 && filename[suffix - 1] != '.'; suffix--)
00286         ;
00287     if (suffix <= 0)
00288         return "text/plain";    // default
00289     
00290     for (i = 0; m[i].suffix; i++)
00291         if (!strncasecmp(filename + suffix, m[i].suffix, filenameLen - suffix))
00292             return m[i].mimetype;
00293     
00294     return "text/plain";    // default
00295 }
00296 
00297 NEErr NEAddOther(NEPtr ne,
00298         char const *filename, int filenameLen,
00299         char const *mimetype)
00300 {
00301     NEStringAdd(&ne->other, filename, filenameLen);
00302     NEStringAdd(&ne->other,
00303             mimetype ? mimetype : SuffixToMimetype(filename, filenameLen),
00304             -1);
00305     return kNEErrOk;
00306 }
00307 
00308 void NEEnumOther(NEPtr ne,
00309         char const **filename,
00310         int *filenameLength)
00311 {
00312     if (*filename)
00313     {
00314         *filename = NEStringNextPart(*filename);    // skip mimetype
00315         *filename = NEStringNextPart(*filename);
00316     }
00317     else
00318         *filename = ne->other;
00319     if (*filename)
00320         *filenameLength = NEStringPartLength(*filename);
00321 }
00322 
00323 NEErr NEAddFile(NEPtr ne,
00324     char const *filename,
00325     char const *path)
00326 {
00327     FILE *fp = NULL;
00328     char *buffer = NULL;
00329     long n;
00330     NEErr err;
00331     
00332     if (!ne->zf)
00333         return kNEErrOk;
00334     
00335     buffer = malloc(kBufferSize);
00336     if (!buffer)
00337         return kNEErrMalloc;
00338     fp = fopen(path, "rb");
00339     if (!fp)
00340     {
00341         free(buffer);
00342         return kNEErrCannotOpenFile;
00343     }
00344     
00345     err = NENewFile(ne, filename);
00346     if (err != kNEErrOk)
00347         goto error;
00348     
00349     for (;;)
00350     {
00351         n = fread(buffer, 1, kBufferSize, fp);
00352         if (n <= 0)
00353             break;
00354         err = NEWriteToFile(ne, buffer, n);
00355         if (err != kNEErrOk)
00356         {
00357             NECloseFile(ne);
00358             goto error;
00359         }
00360     }
00361     
00362     free(buffer);
00363     NECloseFile(ne);
00364     return kNEErrOk;
00365     
00366 error:
00367     if (fp)
00368         fclose(fp);
00369     if (buffer)
00370         free(buffer);
00371     return err;
00372 }
00373 
00374 NEErr NEAddTOCEntry(NEPtr ne, char const *title, char const *relativeUrl, int level)
00375 {
00376     char str[16];
00377     
00378     ne->ncxCount++;
00379     if (level > ne->maxTOCDepth)
00380         ne->maxTOCDepth = level;
00381     
00382     // warning: level isn't used yet
00383     
00384     NEStringCat(&ne->tocEntries, "<navPoint id=\"", -1);
00385     sprintf(str, "p%d", ne->ncxCount);
00386     NEStringCat(&ne->tocEntries, str, -1);
00387     NEStringCat(&ne->tocEntries, "\" playOrder=\"", -1);
00388     sprintf(str, "%d", ne->ncxCount);
00389     NEStringCat(&ne->tocEntries, str, -1);
00390     NEStringCat(&ne->tocEntries, "\"><navLabel><text>", -1);
00391     NEStringCat(&ne->tocEntries, title, -1);
00392     NEStringCat(&ne->tocEntries, "</text></navLabel><content src=\"", -1);
00393     NEStringCat(&ne->tocEntries, relativeUrl, -1);
00394     NEStringCat(&ne->tocEntries, "\"/></navPoint>\n", -1);
00395     
00396     return kNEErrOk;
00397 }
00398 
00399 NEErr NENewFile(NEPtr ne,
00400     char const *filename)
00401 {
00402     int zerr;
00403     char filename2[kPathSize];
00404     
00405     if (!ne->zf)
00406         return kNEErrOk;
00407     
00408     if (filename[0] == '/')
00409     {
00410         // skip slash
00411         strncpy(filename2, filename + 1, kPathSize);
00412     }
00413     else
00414     {
00415         // prepend DOCDIR "/"
00416         strcpy(filename2, DOCDIR "/");
00417         strncat(filename2, filename, kPathSize);
00418     }
00419     
00420     zerr = zipOpenNewFileInZip(ne->zf,
00421             filename2, NULL,
00422             NULL, 0, NULL, 0,
00423             NULL,
00424             Z_DEFLATED, Z_DEFAULT_COMPRESSION);
00425     return zerr == Z_OK ? kNEErrOk : kNEErrZip;
00426 }
00427 
00428 NEErr NEWriteToFile(NEPtr ne,
00429     char const *data, int len)
00430 {
00431     if (!ne->zf)
00432     {
00433         fwrite(data, 1, len >= 0 ? len : strlen(data), stdout); 
00434         return kNEErrOk;
00435     }
00436     
00437     if (len < 0)
00438         len = strlen(data);
00439     return zipWriteInFileInZip(ne->zf, data, len) == Z_OK ? kNEErrOk : kNEErrZip;
00440 }
00441 
00442 NEErr NECloseFile(NEPtr ne)
00443 {
00444     if (!ne->zf)
00445         return kNEErrOk;
00446     return zipCloseFileInZip(ne->zf) == Z_OK ? kNEErrOk : kNEErrZip;
00447 }
00448 
00449 NEErr NEAddEndnote(NEPtr ne,
00450         char const *endnote, int len,
00451         char const *refDoc, int refDocLen,
00452         char const **refLink)
00453 {
00454     char str[16];
00455     NEBoolean beginsWithP, quoted, squoted;
00456     int i;
00457     
00458     sprintf(str, "%d", ++ne->endnoteCount);
00459     
00460     // create refLink = &nbsp;<a href="ENDNOTESDOC#enN" id="enRefN">[N]</a>
00461     NEStringCopy(&ne->lastRefLink, "&nbsp;<a href=\"" ENDNOTESDOC "#en", -1);
00462     NEStringCat(&ne->lastRefLink, str, -1);
00463     NEStringCat(&ne->lastRefLink, "\" id=\"enRef", -1);
00464     NEStringCat(&ne->lastRefLink, str, -1);
00465     NEStringCat(&ne->lastRefLink, "\">[", -1);
00466     NEStringCat(&ne->lastRefLink, str, -1);
00467     NEStringCat(&ne->lastRefLink, "]</a>", -1);
00468     *refLink = ne->lastRefLink;
00469     
00470     // create endnote
00471     // <div class="endnote" id="enN"><p><a href="refDoc#enRefN">[N]</a> endnote</p></div>
00472     // insert hyperlink at the beginning of first p element or prepend a new
00473     //  p element with the hyperlink alone if it is another type (typically pre)
00474     NEStringCat(&ne->endnotes, "<div class=\"endnote\" id=\"en", -1);
00475     NEStringCat(&ne->endnotes, str, -1);
00476     NEStringCat(&ne->endnotes, "\">\n", -1);
00477     beginsWithP = endnote[0] == '<' && endnote[1] == 'p'
00478         && (endnote[2] < 'a' || endnote[2] > 'z')
00479         && (endnote[2] < 'A' || endnote[2] > 'Z');
00480     if (beginsWithP)
00481     {
00482         // find complete p tag (including attributes) until 
00483         for (i = 0, quoted = squoted = FALSE; i < len; i++)
00484             if (!squoted && endnote[i] == '"')
00485                 quoted = !quoted;
00486             else if (!quoted && endnote[i] == '\'')
00487                 squoted = !squoted;
00488             else if (!quoted && !squoted && endnote[i] == '>')
00489                 break;
00490         if (i < len)
00491             i++;
00492         // copy it to ne->endnotes
00493         NEStringCat(&ne->endnotes, endnote, i);
00494     }
00495     else
00496         NEStringCat(&ne->endnotes, "<p>", -1);
00497     // link
00498     NEStringCat(&ne->endnotes, "<a href=\"", -1);
00499     NEStringCat(&ne->endnotes, refDoc, refDocLen);
00500     NEStringCat(&ne->endnotes, "#enRef", -1);
00501     NEStringCat(&ne->endnotes, str, -1);
00502     NEStringCat(&ne->endnotes, "\">[", -1);
00503     NEStringCat(&ne->endnotes, str, -1);
00504     NEStringCat(&ne->endnotes, "]</a>", -1);
00505     if (beginsWithP)
00506     {
00507         NEStringCat(&ne->endnotes, " ", -1);
00508         NEStringCat(&ne->endnotes, endnote + i, len - i);
00509     }
00510     else
00511     {
00512         NEStringCat(&ne->endnotes, "</p>\n", -1);
00513         NEStringCat(&ne->endnotes, endnote, len);
00514     }
00515     NEStringCat(&ne->endnotes, "</div>\n", -1);
00516     
00517     return kNEErrOk;
00518 }
00519 
00520 NEErr NEMakeCover(NEPtr ne)
00521 {
00522     NEErr err;
00523     
00524     Chk(NENewFile(ne, COVERDOC));
00525     Chk(NEWriteToFile(ne,
00526         "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
00527         "<!DOCTYPE html PUBLIC\n"
00528         " \"-//W3C//DTD XHTML 1.1//EN\"\n"
00529         " \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n"
00530         "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n"
00531         "<head>\n"
00532         "<title>Cover</title>\n"
00533         "<style type=\"text/css\">img {max-width: 100%;}</style>\n"
00534         "</head>\n"
00535         "<body class=\"cover\">\n"
00536         , -1));
00537     if (ne->coverImage)
00538     {
00539         Chk(NEWriteToFile(ne, "<div><img src=\"", -1));
00540         Chk(NEWriteToFile(ne, ne->coverImage, -1));
00541         Chk(NEWriteToFile(ne, "\" alt=\"Cover\"/></div>", -1));
00542     }
00543     else
00544     {
00545         Chk(NEWriteToFile(ne,
00546             "<svg version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\"\n"
00547             " xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"
00548             " width=\"100%\" height=\"100%\" viewBox=\"0 0 500 656\">\n"
00549             "<rect x=\"0\" y=\"0\" fill=\"blue\" width=\"500\" height=\"656\"/>\n"
00550             , -1));
00551         if (ne->title)
00552         {
00553             Chk(NEWriteToFile(ne,
00554                 "<text font-family=\"Helvetica\" font-size=\"36\" fill=\"white\" x=\"100\" y=\"350\">"
00555                 , -1));
00556             Chk(NEWriteToFile(ne, ne->title, -1));
00557             Chk(NEWriteToFile(ne,
00558                 "</text>\n"
00559                 , -1));
00560         }
00561         if (ne->creator)
00562         {
00563             Chk(NEWriteToFile(ne,
00564                 "<text font-family=\"Helvetica\" font-size=\"24\" fill=\"white\" x=\"100\" y=\"250\">"
00565                 , -1));
00566             Chk(NEWriteToFile(ne, ne->creator, -1));
00567             Chk(NEWriteToFile(ne,
00568                 "</text>\n"
00569                 , -1));
00570         }
00571         Chk(NEWriteToFile(ne,
00572             "</svg>\n"
00573             , -1));
00574     }
00575     Chk(NEWriteToFile(ne,
00576         "</body>\n"
00577         "</html>\n"
00578         , -1));
00579     Chk(NECloseFile(ne));
00580     Chk(NEStringCopy(&ne->cover, COVERDOC, -1));
00581     return kNEErrOk;
00582 }
00583 
00592 static NEErr WriteMetadata(NEPtr ne,
00593     char const *name, char const *attr, char const *str)
00594 {
00595     char const *sub;
00596     
00597     for (sub = str; sub; sub = NEStringNextPart(sub))
00598     {
00599         NEErr err;
00600         
00601         Chk(NEWriteToFile(ne, "  <dc:", -1));
00602         Chk(NEWriteToFile(ne, name, -1));
00603         if (attr)
00604         {
00605             Chk(NEWriteToFile(ne, " ", -1));
00606             Chk(NEWriteToFile(ne, attr, -1));
00607         }
00608         Chk(NEWriteToFile(ne, ">", -1));
00609         Chk(NEWriteToFile(ne, sub, NEStringPartLength(sub)));
00610         Chk(NEWriteToFile(ne, "</dc:", -1));
00611         Chk(NEWriteToFile(ne, name, -1));
00612         Chk(NEWriteToFile(ne, ">\n", -1));
00613     }
00614     return kNEErrOk;
00615 }
00616 
00623 static NEErr WriteMeta(NEPtr ne,
00624     char const *name, char const *content)
00625 {
00626     NEErr err;
00627     
00628     Chk(NEWriteToFile(ne, "  <meta name=\"", -1));
00629     Chk(NEWriteToFile(ne, name, -1));
00630     Chk(NEWriteToFile(ne, "\" content=\"", -1));
00631     Chk(NEWriteToFile(ne, content, -1));
00632     Chk(NEWriteToFile(ne, "\"/>\n", -1));
00633     
00634     return kNEErrOk;
00635 }
00636 
00641 static NEErr WriteEndnotes(NEPtr ne)
00642 {
00643     NEErr err;
00644     
00645     if (!ne->endnotes)
00646         return kNEErrOk;
00647     
00648     Chk(NENewFile(ne, ENDNOTESDOC));
00649     Chk(NEWriteToFile(ne,
00650         "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
00651         "<!DOCTYPE html PUBLIC\n"
00652         " \"-//W3C//DTD XHTML 1.1//EN\"\n"
00653         " \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n"
00654         "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n"
00655         "<head>\n"
00656         "<title>End Notes</title>\n"
00657         "<style type=\"text/css\">\n"
00658         "div.endnote {page-break-before: always}\n"
00659         "</style>\n"
00660         "</head>\n"
00661         "<body>\n",
00662         -1));
00663     Chk(NEWriteToFile(ne,
00664         ne->endnotes,
00665         -1));
00666     Chk(NEWriteToFile(ne,
00667         "</body>\n"
00668         "</html>\n",
00669         -1));
00670     Chk(NECloseFile(ne));
00671     Chk(NEAddPart(ne, ENDNOTESDOC, TRUE));
00672     
00673     return kNEErrOk;
00674 }
00675 
00680 static NEErr WriteOPF(NEPtr ne)
00681 {
00682     int p;
00683     NEErr err;
00684     char const *sub;
00685     int id;
00686     char idStr[16]; // "idN" where N is 1, 2, ...
00687     
00688     Chk(NENewFile(ne, ROOTDOC));
00689     Chk(NEWriteToFile(ne,
00690         "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
00691         "<package version=\"2.0\"\n"
00692         " unique-identifier=\"PrimaryID\"\n"
00693         " xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n"
00694         " xmlns=\"http://www.idpf.org/2007/opf\">\n"
00695         " <metadata>\n",
00696         -1));
00697     
00698     Chk(NEWriteToFile(ne, "  <dc:identifier id=\"PrimaryID\">", -1));
00699     Chk(NEWriteToFile(ne, ne->identifier, -1));
00700     Chk(NEWriteToFile(ne, "</dc:identifier>\n", -1));
00701     Chk(WriteMetadata(ne, "title", NULL, ne->title));
00702     Chk(WriteMetadata(ne, "creator", NULL /* "opf:role=\"aut\"" */, ne->creator));
00703     Chk(WriteMetadata(ne, "subject", NULL, ne->subject));
00704     Chk(WriteMetadata(ne, "description", NULL, ne->description));
00705     Chk(WriteMetadata(ne, "publisher", NULL, ne->publisher));
00706     Chk(WriteMetadata(ne, "date", NULL, ne->date));
00707     Chk(WriteMetadata(ne, "source", NULL, ne->source));
00708     Chk(WriteMetadata(ne, "language", NULL, ne->language ? ne->language : "en"));
00709     Chk(WriteMetadata(ne, "rights", NULL, ne->rights));
00710     Chk(WriteMeta(ne, "cover", "CoverID"));
00711     
00712     Chk(NEWriteToFile(ne,
00713         " </metadata>\n"
00714         " <manifest>\n",
00715         -1));
00716     Chk(NEWriteToFile(ne,
00717         "  <item id=\"ncx\"\n   href=\""
00718         NCXDOC
00719         "\"\n   media-type=\"application/x-dtbncx+xml\"/>\n",
00720         -1));
00721     for (p = 0, id = 1; p < 3; p++)
00722         for (sub = p == 0 ? ne->cover : p == 1 ? ne->parts : ne->auxParts;
00723             sub;
00724             sub = NEStringNextPart(sub), id++)
00725         {
00726             Chk(NEWriteToFile(ne, "  <item id=\"", -1));
00727             sprintf(idStr, "id%d", id);
00728             Chk(NEWriteToFile(ne, idStr, -1));
00729             Chk(NEWriteToFile(ne, "\"\n   href=\"", -1));
00730             Chk(NEWriteToFile(ne, sub, NEStringPartLength(sub)));
00731             Chk(NEWriteToFile(ne, "\"\n   media-type=\"application/xhtml+xml\"/>\n", -1));
00732         }
00733     for (sub = ne->other; sub; sub = NEStringNextPart(sub), id++)
00734     {
00735         Chk(NEWriteToFile(ne, "  <item id=\"", -1));
00736         sprintf(idStr, "id%d", id);
00737         Chk(NEWriteToFile(ne, idStr, -1));
00738         Chk(NEWriteToFile(ne, "\"\n   href=\"", -1));
00739         Chk(NEWriteToFile(ne, sub, NEStringPartLength(sub)));
00740         sub = NEStringNextPart(sub);
00741         Chk(NEWriteToFile(ne, "\"\n   media-type=\"", -1));
00742         Chk(NEWriteToFile(ne, sub, NEStringPartLength(sub)));
00743         Chk(NEWriteToFile(ne, "\"/>\n", -1));
00744     }
00745     if (ne->coverImage)
00746     {
00747         Chk(NEWriteToFile(ne, "  <item id=\"CoverID\"\n   href=\"", -1));
00748         Chk(NEWriteToFile(ne, ne->coverImage, -1));
00749         Chk(NEWriteToFile(ne, "\"\n   media-type=\"", -1));
00750         Chk(NEWriteToFile(ne, SuffixToMimetype(ne->coverImage, -1), -1));
00751         Chk(NEWriteToFile(ne, "\"/>\n", -1));
00752     }
00753     Chk(NEWriteToFile(ne,
00754         " </manifest>\n"
00755         " <spine toc=\"ncx\">\n",
00756         -1));
00757     for (p = 0, id = 1; p < 3; p++)
00758         for (sub = p == 0 ? ne->cover : p == 1 ? ne->parts : ne->auxParts;
00759             sub;
00760             sub = NEStringNextPart(sub), id++)
00761         {
00762             Chk(NEWriteToFile(ne, " <itemref idref=\"", -1));
00763             sprintf(idStr, "id%d", id);
00764             Chk(NEWriteToFile(ne, idStr, -1));
00765             Chk(NEWriteToFile(ne,
00766                     p == 1 ? "\"/>\n" : "\" linear=\"no\"/>\n", -1));
00767         }
00768     Chk(NEWriteToFile(ne,
00769         " </spine>\n",
00770         -1));
00771     if (ne->cover)
00772     {
00773         Chk(NEWriteToFile(ne,
00774             " <guide>\n"
00775             "  <reference type=\"cover\" title=\"Cover\" href=\"",
00776             -1));
00777         Chk(NEWriteToFile(ne, ne->cover, -1));
00778         Chk(NEWriteToFile(ne,
00779             "\"/>\n"
00780             " </guide>\n",
00781             -1));
00782     }
00783     Chk(NEWriteToFile(ne,
00784         "</package>\n",
00785         -1));
00786     Chk(NECloseFile(ne));
00787     
00788     return kNEErrOk;
00789 }
00790 
00795 static NEErr WriteNCX(NEPtr ne)
00796 {
00797     NEErr err;
00798     char str[16];
00799     
00800     Chk(NENewFile(ne, NCXDOC));
00801     Chk(NEWriteToFile(ne,
00802         "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
00803         "<!DOCTYPE ncx PUBLIC \"-//NISO//DTD ncx 2005-1//EN\" "
00804             "\"http://www.daisy.org/z3986/2005/ncx-2005-1.dtd\">\n"
00805         "<ncx version=\"2005-1\" xml:lang=\"en-US\"\n"
00806         " xmlns=\"http://www.daisy.org/z3986/2005/ncx/\">\n",
00807         -1));
00808     Chk(NEWriteToFile(ne,
00809         " <head>\n",
00810         -1));
00811     Chk(NEWriteToFile(ne,
00812         "  <meta name=\"dtb:uid\" content=\"",
00813         -1));
00814     Chk(NEWriteToFile(ne, ne->identifier, -1));
00815     Chk(NEWriteToFile(ne,
00816         "\"/>\n",
00817         -1));
00818     sprintf(str, "%d", ne->maxTOCDepth);
00819     Chk(NEWriteToFile(ne,
00820         "  <meta name=\"dtb:depth\" content=\"",
00821         -1));
00822     Chk(NEWriteToFile(ne, str, -1));
00823     Chk(NEWriteToFile(ne,
00824         "\"/>\n",
00825         -1));
00826     Chk(NEWriteToFile(ne,
00827         "  <meta name=\"dtb:totalPageCount\" content=\"0\"/>\n",
00828         -1));
00829     Chk(NEWriteToFile(ne,
00830         "  <meta name=\"dtb:maxNumberPage\" content=\"0\"/>\n",
00831         -1));
00832     Chk(NEWriteToFile(ne,
00833         " </head>\n",
00834         -1));
00835     Chk(NEWriteToFile(ne,
00836         " <docTitle><text>",
00837         -1));
00838     Chk(NEWriteToFile(ne, ne->title ? ne->title : "Untitled", -1));
00839     Chk(NEWriteToFile(ne,
00840         "</text></docTitle>\n",
00841         -1));
00842     Chk(NEWriteToFile(ne,
00843         " <navMap>\n",
00844         -1));
00845     if (ne->tocEntries)
00846         Chk(NEWriteToFile(ne, ne->tocEntries, -1));
00847     Chk(NEWriteToFile(ne,
00848         " </navMap>\n",
00849         -1));
00850     Chk(NEWriteToFile(ne,
00851         "</ncx>\n",
00852         -1));
00853     Chk(NECloseFile(ne));
00854     
00855     return kNEErrOk;
00856 }
00857 
00858 NEErr NEEnd(NEPtr ne)
00859 {
00860     int zerr;
00861     NEErr err;
00862     
00863     Chk(WriteEndnotes(ne));
00864     Chk(WriteOPF(ne));
00865     Chk(WriteNCX(ne));
00866     
00867     // write META-INF/container.xml
00868     Chk(NENewFile(ne, "/META-INF/container.xml"));
00869     Chk(NEWriteToFile(ne,
00870         "<?xml version=\"1.0\"?>\n"
00871         "<container version=\"1.0\" "
00872         " xmlns=\"urn:oasis:names:tc:opendocument:xmlns:container\">\n"
00873         " <rootfiles>\n"
00874         "  <rootfile full-path=\"" DOCDIR "/" ROOTDOC "\""
00875         "   media-type=\"application/oebps-package+xml\"/>\n"
00876         " </rootfiles>\n"
00877         "</container>\n"
00878         , -1));
00879     Chk(NECloseFile(ne));
00880     
00881     zerr = zipClose(ne->zf, NULL);
00882     
00883     // release all resources
00884     NEStringFree(&ne->title);
00885     NEStringFree(&ne->creator);
00886     NEStringFree(&ne->identifier);
00887     NEStringFree(&ne->language);
00888     NEStringFree(&ne->subject);
00889     NEStringFree(&ne->description);
00890     NEStringFree(&ne->publisher);
00891     NEStringFree(&ne->date);
00892     NEStringFree(&ne->source);
00893     NEStringFree(&ne->rights);
00894     NEStringFree(&ne->endnotes);
00895     NEStringFree(&ne->lastRefLink);
00896     NEStringFree(&ne->parts);
00897     NEStringFree(&ne->auxParts);
00898     NEStringFree(&ne->cover);
00899     NEStringFree(&ne->coverImage);
00900     NEStringFree(&ne->other);
00901     NEStringFree(&ne->tocEntries);
00902     
00903     if (zerr != Z_OK)
00904         return kNEErrZip;
00905     return kNEErrOk;
00906 }
Generated by Doxygen.
Copyright 2007-2013, Yves Piguet.
All rights reserved.