1 /*
2  * << H a r u --free pdf library >> -- DocMaker.cpp
3  *
4  * Copyright (c) 1999-2002 Takeshi Kanno <takeshi_kanno@est.hi-ho.ne.jp>
5  *
6  * Permission to use, copy, modify, distribute and sell this software
7  * and its documentation for any purpose is hereby granted without fee,
8  * provided that the above copyright notice appear in all copies and
9  * that both that copyright notice and this permission notice appear
10  * in supporting documentation.
11  * It is provided "as is" without express or implied warranty.
12  *
13  * 2002.10.21 create.
14  *
15  *     %T<title> <VERSION> <DATE>
16  *                               --- Add front page with specified parameters.
17  *     %S<title> <section-no>    --- Add section named <title> with level n.
18  *     %I<title> <image-file-name> <width> <height>
19  *                               --- Insert image file.
20  *     %W<title> <WMF-file-name> <width> <height>
21  *                               --- Insert WMF file with specified size.
22  *     other                     --- Show text at current position.
23  *
24  */
25 
26 #include <assert.h>
27 #include "libharu.h"
28 #include "libharu_wmf.h"
29 
30 #define LEFT_MARGIN   85
31 #define RIGHT_MARGIN  LEFT_MARGIN
32 #define TOP_MARGIN    50
33 #define BOTTOM_MARGIN TOP_MARGIN + 10
34 #define IMAGE_SPACE   20
35 #define PAGE_WIDTH    530
36 #define PAGE_HEIGHT   665
37 
38 const double BASE_RIGHT = PAGE_WIDTH - RIGHT_MARGIN;
39 const double BASE_TOP = PAGE_HEIGHT - TOP_MARGIN;
40 
41 static const int PDF_CHAR_SIZE_TITLE0 = 35;
42 static const int PDF_CHAR_SIZE_TITLE1 = 18;
43 static const int PDF_CHAR_SIZE_TITLE2 = 10;
44 static const int PDF_CHAR_SIZE_TITLE3 = 10;
45 static const int PDF_CHAR_SIZE_DEFAULT = 10;
46 static const int PDF_CHAR_SIZE_SMALL = 8;
47 
48 class DocMaker;
49 
50 class DocIndex
51 {
52     friend class    DocMaker;
53 public:
54                     DocIndex(int level, const char* title,
55                             PdfDestination* desti, int page, int chapter1,
56                             int chapter2);
57                     ~DocIndex();
58 private:
59     PdfDestination* fDest;
60     char*           fTitle;
61     int             fPage;
62     int             fLevel;
63     int             fChapter[2];
64 };
65 
66 class DocMaker
67 {
68 public:
69                     DocMaker();
70                     ~DocMaker();
71     void            WriteBackground(PdfContents* canvas);
GetCurrent()72     PdfPage*        GetCurrent()        { return fContentsPage; }
GetCurrentIdx()73     PdfPage*        GetCurrentIdx()     { return fIndexPage; }
74     void            AddTitle(const char* buf);
75     void            AddSection(const char* title, int level);
76     void            ShowText(const char* text);
77     void            ShowImage(const char* title, const char* filename,
78                             double width = 0, double height = 0);
79     void            ShowWMFImage(const char* title, const char* filename,
80                             double width = 0, double height = 0);
WriteToFile(const char * filename)81     void            WriteToFile(const char* filename)
82                         { fDoc->WriteToFile(filename); }
83     const char*     GetStrParam(const char* str, char* param, int len);
84     const char*     GetIntParam(const char* str, int* param);
85     const char*     GetFloatParam(const char* str, double* param);
86     void            MakeIndex();
87     void            MakeOutline();
88     void            SetDocName(const char* docname);
89     void            SetFont(const char* name);
90     void            SetIndent(int level);
91     void            ShowLabel(const char* text, int indent);
CurLine()92     int             CurLine()           { return fCurLine; }
IncCurLine()93     void            IncCurLine()        { fCurLine++; }
94     void            IncLine();
95 private:
96     void            DrawPageBack(PdfContents* canvas, double top,
97                         bool show_pageno = true);
98     void            AddIndexPage();
99     void            AddPage();
100     PdfDoc*         fDoc;
101     PdfContents*    fCanvas;
102     PdfPages*       fContentsPages;
103     PdfPages*       fFrontPages;
104     PdfPage*        fFrontPage;
105     PdfPages*       fIndexPages;
106     PdfPage*        fContentsPage;
107     PdfDestination* fContentsDst;
108     PdfPage*        fIndexPage;
109     int             fSection[3];
110     int             fFigureNo;
111     int             fImageNo;
112     double           fIndexYPos;
113     double           fPageYPos;
114     int             fXMargine;
115     char            fCurFont[64];
116     int             fCurFontSize;
117     int             fPage;
118     char            fTitle[256];
119     char*           fDocName;
120     int             fImageIdx;
121     double           fTmpXPos;
122     double           fTmpYPos;
123     double           fLeftMargin;
124     bool            fAdjustFlg;
125     PdfList*        fIndexes;
126     int             fCurLine;
127 };
128 
DocIndex(int level,const char * title,PdfDestination * dest,int page,int chapter_1,int chapter_2)129 DocIndex::DocIndex(int level, const char* title, PdfDestination* dest,
130         int page, int chapter_1, int chapter_2)
131 {
132     int len = strlen(title);
133     fTitle = new char[len + 1];
134     strncpy(fTitle, title, len);
135     fTitle[len] = 0x00;
136     fDest = dest;
137     fPage = page;
138     fLevel = level;
139     fChapter[0] = chapter_1;
140     fChapter[1] = chapter_2;
141 }
142 
143 
~DocIndex()144 DocIndex::~DocIndex()
145 {
146     if (fTitle != NULL)
147         delete[] fTitle;
148 }
149 
DocMaker()150 DocMaker::DocMaker()
151 {
152     fDoc = new PdfDoc;
153     fDoc->NewDoc();
154 
155     PDF_DEBUG_PRINT(("DocMaker::DocMaker()\n"));
156 
157     /* Set PageMode and PageLayout. */
158     fDoc->Catalog()->SetPageMode(PDF_USE_OUTLINES);
159     fDoc->Catalog()->SetPageLayout(PDF_ONE_COLUMN);
160     fDoc->Catalog()->AddPageLabel(0, PDF_PAGE_NUM_LOWER_ROMAN);
161     fDoc->RootPages()->SetSize(PAGE_WIDTH, PAGE_HEIGHT);
162 
163     PdfInfo* info = fDoc->Info();
164     info->SetCreator("DocMaker");
165 
166     time_t ct = time(NULL);
167     struct tm* lst = localtime(&ct);
168     pdf_date date = {lst->tm_year + 1900, lst->tm_mon + 1, lst->tm_mday,
169         lst->tm_hour, lst->tm_min, lst->tm_sec, '-', 0, 0};
170 
171     info->SetCreationDate(date);
172 
173     /* Create Pages objects. */
174     PDF_DEBUG_PRINT(("DocMaker::DocMaker() --create pages\n"));
175     fFrontPages = fDoc->RootPages()->AddPages();
176     fIndexPages = fDoc->RootPages()->AddPages();
177     fContentsPages = fDoc->RootPages()->AddPages();
178 
179     /* Create Font objects. */
180     PDF_DEBUG_PRINT(("DocMaker::DocMaker() --create fonts\n"));
181     PdfType1FontDef* fd = new PdfHelveticaFontDef();
182     PdfEncodingDef* encoding = new PdfWinAnsiEncoding();
183     fDoc->AddType1Font(fd, NULL, encoding);
184 
185     fd = new PdfHelveticaBoldFontDef();
186     fDoc->AddType1Font(fd, NULL, encoding);
187 
188     fd = new PdfHelveticaObliqueFontDef();
189     fDoc->AddType1Font(fd, NULL, encoding);
190 
191     fd = new PdfTimesRomanFontDef();
192     fDoc->AddType1Font(fd, NULL, encoding);
193 
194     fd = new PdfTimesItalicFontDef();
195     fDoc->AddType1Font(fd, NULL, encoding);
196 
197     fd = new PdfTimesBoldFontDef();
198     fDoc->AddType1Font(fd, NULL, encoding);
199 
200     fd = new PdfCourierFontDef();
201     fDoc->AddType1Font(fd, NULL, encoding);
202 
203     fd = new PdfSymbolFontDef();
204     fDoc->AddType1Font(fd);
205 
206     strncpy(fCurFont, "Times-Roman", 64);
207     fCurFontSize = PDF_CHAR_SIZE_DEFAULT;
208     fLeftMargin = LEFT_MARGIN;
209     fIndexYPos = 70;
210     fSection[0] = 0;
211     fSection[1] = 0;
212     fSection[2] = 0;
213     fPage = 0;
214 
215     fImageIdx = 0;
216     fDocName = NULL;
217     fFrontPage = NULL;
218     fIndexes = new PdfList();
219     fCurLine = 0;
220     PDF_DEBUG_PRINT(("DocMaker::DocMaker() --end\n"));
221 }
222 
~DocMaker()223 DocMaker::~DocMaker()
224 {
225     for (int i = 0; i < fIndexes->CountItems(); i++)
226         delete (DocIndex*)fIndexes->ItemAt(i);
227 
228     if (fDocName != NULL)
229         delete[] fDocName;
230 
231     delete fIndexes;
232     delete fDoc;
233 }
234 
235 void
MakeIndex()236 DocMaker::MakeIndex()
237 {
238     char buf[255];
239 
240     PDF_DEBUG_PRINT(("DocMaker::MakeIndex()\n"));
241     AddIndexPage();
242 
243     fContentsDst = new PdfDestination(fIndexPage);
244     fContentsDst->SetFit();
245 
246     fCanvas = fIndexPage->Canvas();
247     fCanvas->SetFontAndSize("Helvetica-Bold", PDF_CHAR_SIZE_TITLE1);
248     fCanvas->BeginText();
249 
250     double tw = fCanvas->TextWidth("Contents");
251     double xpos = (fCanvas->Width() - LEFT_MARGIN - RIGHT_MARGIN -
252             tw) / 2 + LEFT_MARGIN;
253     fCanvas->MoveTextPos(xpos, BASE_TOP - 60);
254     fCanvas->ShowText("Contents");
255     fCanvas->EndText();
256 
257     fCanvas->SetFontAndSize("Helvetica-Bold", PDF_CHAR_SIZE_TITLE3);
258     fCanvas->BeginText();
259     fCanvas->MoveTextPos(LEFT_MARGIN + 60, BASE_TOP - 80);
260 
261     fPageYPos = BASE_TOP - 80;
262 
263     for (int i = 0; i < fIndexes->CountItems(); i++) {
264         DocIndex* idx = (DocIndex*)fIndexes->ItemAt(i);
265 
266         if (idx->fLevel == 0) {
267             fCanvas->MoveTextPos(0, -25);
268             snprintf(buf, 255, "Chapter %d: %s", idx->fChapter[0],
269                     idx->fTitle);
270             fCanvas->SetFontAndSize("Helvetica-Bold", PDF_CHAR_SIZE_TITLE3);
271             PdfLinkAnnot* annot = fIndexPage->AddLink(PdfRect(
272                         fCanvas->TextPos().x,
273                         fCanvas->TextPos().y,
274                         fCanvas->TextPos().x + fCanvas->TextWidth(buf),
275                         fCanvas->TextPos().y + PDF_CHAR_SIZE_TITLE3),
276                         idx->fDest);
277             annot->SetBorder(0, 0, 0);
278             fCanvas->ShowText(buf);
279             fCanvas->MoveTextPos(0, -5);
280 
281             fPageYPos -= 30;
282         } else {
283             fCanvas->MoveTextPos(-30, -15);
284             snprintf(buf, 255, "%d.%d", idx->fChapter[0], idx->fChapter[1]);
285             fCanvas->SetFontAndSize("Times-Roman", PDF_CHAR_SIZE_DEFAULT);
286             fCanvas->ShowText(buf);
287             fCanvas->MoveTextPos(30, 0);
288             PdfLinkAnnot* annot = fIndexPage->AddLink(PdfRect(
289                         fCanvas->TextPos().x,
290                         fCanvas->TextPos().y,
291                         fCanvas->TextPos().x + fCanvas->TextWidth(idx->fTitle),
292                         fCanvas->TextPos().y + PDF_CHAR_SIZE_DEFAULT),
293                         idx->fDest);
294             annot->SetBorder(0, 0, 0);
295             fCanvas->ShowText(idx->fTitle);
296 
297             fPageYPos -= 15;
298         }
299         if (fPageYPos < BOTTOM_MARGIN + PDF_CHAR_SIZE_TITLE2 * 2) {
300             fCanvas->EndText();
301             AddIndexPage();
302             fCanvas = fIndexPage->Canvas();
303             fCanvas->BeginText();
304             fCanvas->MoveTextPos(LEFT_MARGIN + 60, BASE_TOP - 60);
305             fPageYPos = BASE_TOP - 60;
306         }
307     }
308     fCanvas->EndText();
309 
310     unsigned int idx_count = fIndexPages->GetKidsCount() + 1;
311     fDoc->Catalog()->AddPageLabel(idx_count, PDF_PAGE_NUM_DECIMAL);
312 }
313 
314 
315 void
MakeOutline()316 DocMaker::MakeOutline()
317 {
318     PDF_DEBUG_PRINT(("DocMaker::MakeOutline()\n"));
319     PdfOutlineItem* root = new PdfOutlineItem(fDoc->Outlines());
320     if (fDocName != NULL)
321         root->SetTitle(fDocName);
322     else
323         root->SetTitle("no title.");
324     root->SetOpened(true);
325     if (fFrontPage != NULL) {
326         PdfDestination* dst = new PdfDestination(fFrontPage);
327         root->SetDestination(dst);
328         fDoc->Catalog()->SetOpenAction(dst);
329     }
330 
331     PdfOutlineItem* item = new PdfOutlineItem(root);
332     item->SetTitle("Contents");
333     item->SetDestination(fContentsDst);
334 
335     for (int i = 0; i < fIndexes->CountItems(); i++) {
336         DocIndex* idx = (DocIndex*)fIndexes->ItemAt(i);
337 
338         if (idx->fLevel == 0) {
339             char buf[255];
340             item = new PdfOutlineItem(root);
341             snprintf(buf, 255, "%d %s", idx->fChapter[0], idx->fTitle);
342             item->SetTitle(buf);
343             item->SetDestination(idx->fDest);
344         } else {
345             char buf[255];
346             PdfOutlineItem* tmp_item = new PdfOutlineItem(item);
347             snprintf(buf, 255, "%d.%d %s", idx->fChapter[0],
348                     idx->fChapter[1], idx->fTitle);
349             tmp_item->SetTitle(buf);
350             tmp_item->SetDestination(idx->fDest);
351         }
352     }
353 }
354 
355 void
DrawPageBack(PdfContents * canvas,double top,bool show_pageno)356 DocMaker::DrawPageBack(PdfContents* canvas, double top, bool show_pageno)
357 {
358     PDF_DEBUG_PRINT(("DocMaker::DrawPageBack()\n"));
359     try {
360         double pw = canvas->Width();
361 
362         canvas->SetLineWidth(0.5);
363         canvas->MoveTo(LEFT_MARGIN, top);
364         canvas->LineTo(BASE_RIGHT, top);
365         canvas->MoveTo(LEFT_MARGIN, top + 8);
366         canvas->LineTo(LEFT_MARGIN, top - 2);
367         canvas->MoveTo(BASE_RIGHT, top + 8);
368         canvas->LineTo(BASE_RIGHT, top - 2);
369         canvas->MoveTo(pw / 2, top + 4);
370         canvas->LineTo(pw / 2, top - 2);
371         canvas->Stroke();
372 
373         /* print page number */
374         if (show_pageno && fPage > 0) {
375             char tmp_page[10];
376 
377             snprintf(tmp_page, 10, "%d", fPage);
378 
379             canvas->BeginText();
380             canvas->SetFontAndSize("Helvetica", 8);
381             double tw = canvas->TextWidth(tmp_page);
382             canvas->MoveTextPos((pw - tw) / 2, top + 6);
383             canvas->ShowText(tmp_page);
384 
385             canvas->EndText();
386         }
387     } catch (PdfException& e) {
388         fprintf(stderr, "%s\n", e.what());
389     }
390 
391     return;
392 }
393 
394 void
AddIndexPage()395 DocMaker::AddIndexPage()
396 {
397     PDF_DEBUG_PRINT(("DocMaker::AddIndexPage()\n"));
398     fIndexPage = fIndexPages->AddPage();
399 
400     PdfContents* canvas = fIndexPage->Canvas();
401     canvas->AddFilter(PDF_FILTER_DEFLATE);
402 
403     DrawPageBack(canvas, BASE_TOP, false);
404 }
405 
406 void
ShowLabel(const char * text,int indent)407 DocMaker::ShowLabel(const char* text, int indent)
408 {
409     PDF_DEBUG_PRINT(("DocMaker::ShowLabel()\n"));
410 /*  double sava_pos = fPageYPos; */
411 /*  double sava_fsize = fCanvas->FontSize(); */
412     char save_font[64];
413     memset(save_font, 0x00, 64);
414     strncpy(save_font, fCanvas->FontName(), 63);
415 
416     SetFont("Helvetica-Bold");
417     fCurFontSize -= 1;
418     SetIndent(0);
419     ShowText(text);
420     SetFont("Times-Roman");
421     fCurFontSize += 1;
422     SetIndent(indent);
423 /*    fPageYPos = sava_pos - 1; */
424     fPageYPos += fCanvas->TextLeading();
425 }
426 
427 void
IncLine()428 DocMaker::IncLine()
429 {
430     fPageYPos -= PDF_CHAR_SIZE_DEFAULT / 2;
431 }
432 
433 void
ShowText(const char * text)434 DocMaker::ShowText(const char* text)
435 {
436     PDF_DEBUG_PRINT(("DocMaker::ShowText()\n"));
437     if (strlen(text) == 0) {
438         fPageYPos -= fCurFontSize;
439         return;
440     }
441 
442     double w = fCanvas->Width() - LEFT_MARGIN - RIGHT_MARGIN;
443     const char* tmp_txt = text;
444 
445     fCanvas->BeginText();
446     fCanvas->SetFontAndSize(fCurFont, fCurFontSize);
447     fCanvas->MoveTextPos(fLeftMargin, fPageYPos + (fCurFontSize - 2));
448 
449     unsigned int num_char = 0;
450     char buf[1024];
451 
452     while (num_char < strlen(text)) {
453 
454         unsigned int nc = fCanvas->MeasureText(tmp_txt, w);
455         assert(nc < 1024);
456 
457         if (fPageYPos < BOTTOM_MARGIN) {
458             fCanvas->EndText();
459             AddPage();
460             fCanvas->BeginText();
461             fCanvas->SetFontAndSize(fCurFont, fCurFontSize);
462             fCanvas->MoveTextPos(fLeftMargin, fPageYPos +
463                     (fCurFontSize - 2));
464         }
465 
466         memset(buf, 0x00, 1024);
467         memcpy(buf, tmp_txt, nc);
468 
469         /* adjustting text widths with setting character space. */
470         if (num_char + nc < strlen(text)) {
471             double tw = fCanvas->TextWidth(buf);
472             double cs = (w - tw) / nc;
473             fCanvas->SetCharSpace(cs);
474         }
475         fCanvas->ShowTextNextLine(buf);
476         fCanvas->SetCharSpace(0);
477         fPageYPos -= fCanvas->TextLeading();
478 
479         num_char += nc;
480         tmp_txt += nc;
481     }
482     fCanvas->EndText();
483     fTmpXPos = fLeftMargin;
484     fTmpYPos = 0;
485     fAdjustFlg = false;
486 }
487 
488 void
AddSection(const char * title,int level)489 DocMaker::AddSection(const char* title, int level)
490 {
491     char buf[255];
492 
493     PDF_DEBUG_PRINT(("DocMaker::AddSection()\n"));
494     if (level == 0) {
495         double tw;
496         double xpos;
497 
498         fTitle[255] = 0x00;
499         strncpy(fTitle, title, 255);
500         fSection[0]++;
501         fSection[1] = 0;
502         fSection[2] = 0;
503         fFigureNo = 0;
504         fImageNo = 0;
505         AddPage();
506         fCanvas->SetFontAndSize("Helvetica-Bold", PDF_CHAR_SIZE_TITLE3);
507         fCanvas->BeginText();
508         snprintf(buf, 255, "CHAPTER %2d", fSection[0]);
509 
510         tw = fCanvas->TextWidth(buf);
511         xpos = (fCanvas->Width() - LEFT_MARGIN - RIGHT_MARGIN -
512                           tw) / 2 + LEFT_MARGIN;
513         fCanvas->MoveTextPos(xpos, BASE_TOP - 60);
514         fCanvas->ShowText(buf);
515         fCanvas->EndText();
516 
517         fCanvas->MoveTo(xpos, BASE_TOP - 64);
518         fCanvas->LineTo(xpos + tw, BASE_TOP - 64);
519         fCanvas->ClosePathStroke();
520 
521         fCanvas->SetFontAndSize("Helvetica-Bold", PDF_CHAR_SIZE_TITLE1);
522         fCanvas->BeginText();
523 
524         tw = fCanvas->TextWidth(title);
525         xpos = (fCanvas->Width() - LEFT_MARGIN - RIGHT_MARGIN -
526                         tw) / 2 + LEFT_MARGIN;
527         fCanvas->MoveTextPos(xpos, BASE_TOP - 105);
528         fCanvas->ShowText(title);
529         fCanvas->EndText();
530 
531         fPageYPos = BASE_TOP - 140;
532         fAdjustFlg = false;
533     } else if (level == 1) {
534         fSection[1]++;
535         fSection[2] = 0;
536 
537         if (fPageYPos < (BOTTOM_MARGIN + PDF_CHAR_SIZE_TITLE2 +
538                     PDF_CHAR_SIZE_DEFAULT))
539             AddPage();
540 
541         fCanvas->SetFontAndSize("Helvetica-Bold", PDF_CHAR_SIZE_TITLE2);
542         fCanvas->BeginText();
543 
544         snprintf(buf, 255, "%d.%d ", fSection[0], fSection[1]);
545         if (fAdjustFlg == true)
546             fPageYPos -= PDF_CHAR_SIZE_TITLE2;
547         else
548             fPageYPos -= PDF_CHAR_SIZE_TITLE2 + 10;
549         fCanvas->MoveTextPos(LEFT_MARGIN - fCanvas->TextWidth(buf), fPageYPos);
550         fCanvas->ShowText(buf);
551         fCanvas->ShowText(title);
552         fPageYPos -= (PDF_CHAR_SIZE_TITLE2 + 5);
553 
554         fCanvas->EndText();
555         fAdjustFlg = true;
556     } else {
557         fSection[2]++;
558 
559         if (fPageYPos < (BOTTOM_MARGIN + PDF_CHAR_SIZE_TITLE3 +
560                     PDF_CHAR_SIZE_DEFAULT))
561             AddPage();
562 
563         fCanvas->SetFontAndSize("Helvetica-Bold", PDF_CHAR_SIZE_TITLE3);
564         fCanvas->BeginText();
565 
566         snprintf(buf, 255, "%d.%d.%d ", fSection[0], fSection[1], fSection[2]);
567         if (fAdjustFlg == true)
568             fPageYPos -= PDF_CHAR_SIZE_TITLE3 - 5;
569         else
570             fPageYPos -= PDF_CHAR_SIZE_TITLE3 + 5;
571         fCanvas->MoveTextPos(LEFT_MARGIN - fCanvas->TextWidth(buf), fPageYPos);
572         fCanvas->ShowText(buf);
573         fCanvas->ShowText(title);
574         fPageYPos -= (PDF_CHAR_SIZE_TITLE2 + 5);
575 
576         fCanvas->EndText();
577         fAdjustFlg = true;
578     }
579 
580     if (level <= 1) {
581         PdfDestination* dst = new PdfDestination(fCanvas->Page());
582         if (level != 0)
583             dst->SetFitH(fPageYPos + 30);
584         DocIndex* di = new DocIndex(level, title, dst, 0, fSection[0],
585                 fSection[1]);
586         fIndexes->AddItem(di);
587     }
588     SetIndent(0);
589 }
590 
591 void
ShowImage(const char * title,const char * filename,double width,double height)592 DocMaker::ShowImage(const char* title, const char* filename,
593         double width, double height)
594 {
595     char s[1024];
596     double img_width;
597     double img_height;
598 
599     PDF_DEBUG_PRINT(("DocMaker::ShowImage()\n"));
600     PdfPngImage* image = new PdfPngImage(fDoc);
601     image->AddFilter(PDF_FILTER_DEFLATE);
602 
603     try {
604         image->LoadFromFile(filename);
605     } catch (PdfException& e) {
606         fprintf(stderr, "ERROR: failed to load image[%s].\n", filename);
607         delete image;
608         exit(1);
609     }
610     try {
611         fDoc->AddXObject(image);
612     } catch (...) {
613         delete image;
614         return;
615     }
616 
617     if (width == 0)
618         img_width = image->Width();
619     else
620         img_width = width;
621 
622     if (height == 0)
623         img_height = image->Height();
624     else
625         img_height = height;
626 
627     if (fCanvas->Width() - RIGHT_MARGIN < fTmpXPos + img_width ||
628             fTmpYPos - img_height - 40 < fPageYPos) {
629         if (fPageYPos - img_height < BOTTOM_MARGIN + 10)
630             AddPage();
631         fTmpYPos = fPageYPos;
632         fPageYPos -= (img_height + 40);
633         fTmpXPos = LEFT_MARGIN;
634         fTmpYPos = 0;
635     }
636 
637     double base_ypos = fPageYPos + 20 + PDF_CHAR_SIZE_SMALL + 4;
638 
639     fCanvas->GSave();
640     fCanvas->Concat(img_width, 0, 0, img_height, fTmpXPos, base_ypos);
641     fCanvas->ExecuteXObject(image);
642     fCanvas->GRestore();
643 
644     fImageNo++;
645     snprintf(s, 1024, "IMAGE %d.%d  ", fSection[0], fImageNo);
646 
647     fCanvas->BeginText();
648     fCanvas->SetFontAndSize("Helvetica-Bold", PDF_CHAR_SIZE_SMALL);
649     fCanvas->MoveTextPos(fTmpXPos, fPageYPos + 20);
650     fCanvas->ShowText(s);
651     fCanvas->SetFontAndSize("Times-Roman", PDF_CHAR_SIZE_DEFAULT);
652     fCanvas->ShowText(title);
653     fCanvas->EndText();
654     fCanvas->SetFontAndSize(fCurFont, fCurFontSize);
655 
656     fTmpXPos += width + IMAGE_SPACE;
657 }
658 
659 void
ShowWMFImage(const char * title,const char * filename,double width,double height)660 DocMaker::ShowWMFImage(const char* title, const char* filename,
661         double width, double height)
662 {
663     char s[1024];
664     double img_width;
665     double img_height;
666 
667     PDF_DEBUG_PRINT(("DocMaker::ShowWMFImage()\n"));
668     img_width = width;
669     img_height = height;
670 
671     if (fCanvas->Width() - RIGHT_MARGIN < fTmpXPos + img_width ||
672             fTmpYPos - img_height - 40 < fPageYPos) {
673         if (fPageYPos - img_height < BOTTOM_MARGIN + 10)
674             AddPage();
675         fTmpYPos = fPageYPos;
676         fPageYPos -= (img_height + 40);
677         fTmpXPos = LEFT_MARGIN;
678         fTmpYPos = 0;
679     }
680 
681     double base_ypos = fPageYPos + 20 + PDF_CHAR_SIZE_SMALL + 4;
682 
683     PdfWMFLoader* loader = new PdfWMFLoader();
684     pdf_rect rect = PdfRect(fTmpXPos, base_ypos - img_height,
685             fTmpXPos + img_width, base_ypos);
686     loader->DrawWMFImage(filename, fCanvas, rect);
687 
688     fCanvas->Rectangle(fTmpXPos, base_ypos, width, height);
689     fCanvas->Stroke();
690 
691     fFigureNo++;
692     snprintf(s, 1024, "IMAGE %d.%d  ", fSection[0], fFigureNo);
693 
694 
695     fCanvas->BeginText();
696     fCanvas->SetFontAndSize("Helvetica-Bold", PDF_CHAR_SIZE_SMALL);
697     fCanvas->MoveTextPos(fTmpXPos, fPageYPos + 20);
698     fCanvas->ShowText(s);
699     fCanvas->SetFontAndSize("Times-Roman", PDF_CHAR_SIZE_DEFAULT);
700     fCanvas->ShowText(title);
701     fCanvas->EndText();
702     fCanvas->SetFontAndSize(fCurFont, fCurFontSize);
703 
704     fTmpXPos += width + IMAGE_SPACE;
705 }
706 
707 void
AddPage()708 DocMaker::AddPage()
709 {
710     PDF_DEBUG_PRINT(("DocMaker::AddPage()\n"));
711     fContentsPage = fContentsPages->AddPage();
712     fCanvas = fContentsPage->Canvas();
713     fCanvas->SetFontAndSize(fCurFont, fCurFontSize);
714     fCanvas->SetTextLeading(PDF_CHAR_SIZE_DEFAULT + 2);
715     fCanvas->AddFilter(PDF_FILTER_DEFLATE);
716 
717     fPage++;
718     WriteBackground(fCanvas);
719 
720     fPageYPos = BASE_TOP - 30;
721     fTmpXPos = LEFT_MARGIN;
722     fTmpYPos = 0;
723 }
724 
725 void
WriteBackground(PdfContents * canvas)726 DocMaker::WriteBackground(PdfContents* canvas)
727 {
728     PDF_DEBUG_PRINT(("DocMaker::WriteBackground()\n"));
729     DrawPageBack(canvas, BASE_TOP);
730 
731     canvas->SetFontAndSize("Helvetica", 8);
732 
733     /* print title text */
734     int tmp_len;
735     if (fTitle != NULL) {
736         tmp_len = strlen(fTitle);
737 
738         const int FIX_LEN = 20;
739         char *tmp_title = new char[tmp_len + FIX_LEN + 1];
740 
741         try {
742             snprintf(tmp_title, tmp_len + FIX_LEN, "%d.%s ", fSection[0],
743                     fTitle);
744 
745             canvas->BeginText();
746             canvas->SetFontAndSize("Helvetica-Oblique", 8);
747             double tw = canvas->TextWidth(tmp_title);
748             canvas->MoveTextPos(BASE_RIGHT - tw - 5, BASE_TOP + 4);
749             canvas->ShowText(tmp_title);
750 
751             canvas->EndText();
752         } catch (PdfException& e) {
753             fprintf(stderr, "%s\n", e.what());
754         }
755         delete[] tmp_title;
756     }
757 
758     return;
759 }
760 
761 const char*
GetStrParam(const char * str,char * param,int len)762 DocMaker::GetStrParam(const char* str, char* param, int len)
763 {
764     if (param == NULL)
765         return NULL;
766     *param = 0x00;
767 
768     if (str == NULL)
769         return NULL;
770 
771     const char* src = str;
772     char* dst = param;
773     bool intext = false;
774 
775     for (int i = 0; i < len; src++){
776         if (*src == 0x00) {
777             *dst = *src;
778             return NULL;
779         } else if (*src == '"')
780             intext = !intext;
781         else if (!intext &&
782                 (*src == ' ' || *src == 0x0d || *src == 0x0a || *src == 0x09)) {
783             if (dst != param) {
784                 *dst = 0x00;
785                 if (*src == 0x0d || *src == 0x0a)
786                     return NULL;
787                 else
788                     return src++;
789             }
790         } else  {
791             *dst++ = *src;
792         }
793     }
794 
795     return NULL;
796 }
797 
798 const char*
GetIntParam(const char * str,int * param)799 DocMaker::GetIntParam(const char* str, int* param)
800 {
801     char sparam[11];
802 
803     str = GetStrParam(str, sparam, 11);
804     int i = atoi(sparam);
805     *param = i;
806 
807     return str;
808 }
809 
810 const char*
GetFloatParam(const char * str,double * param)811 DocMaker::GetFloatParam(const char* str, double* param)
812 {
813     char sparam[11];
814 
815     str = GetStrParam(str, sparam, 11);
816     double f = atof(sparam);
817     *param = f;
818 
819     return str;
820 }
821 
822 void
SetDocName(const char * docname)823 DocMaker::SetDocName(const char* docname)
824 {
825     if (fDocName != NULL)
826         delete[] fDocName;
827 
828     int len = strlen(docname) + 1;
829     fDocName = new char[len];
830     strcpy(fDocName, docname);
831 }
832 
833 void
AddTitle(const char * buf)834 DocMaker::AddTitle(const char* buf)
835 {
836     char tmpbuf[255];
837 
838     PDF_DEBUG_PRINT(("DocMaker::AddTitle(%s)\n", buf));
839     fFrontPage = fFrontPages->AddPage();
840     PdfContents* canvas = fFrontPage->Canvas();
841     canvas->AddFilter(PDF_FILTER_DEFLATE);
842 
843     /* Print the document title. */
844     buf = GetStrParam(buf, tmpbuf, 255);
845     if (tmpbuf == NULL)
846         return;
847 
848     SetDocName(tmpbuf);
849     canvas->BeginText();
850     canvas->SetFontAndSize("Helvetica-Bold", PDF_CHAR_SIZE_TITLE0);
851     canvas->MoveTextPos(75, 500);
852     int numchars = 0;
853     double width = canvas->TextWidth(tmpbuf, &numchars);
854     double tmpw = canvas->Width() - 75 * 2 - width;
855     canvas->SetCharSpace(tmpw / numchars);
856 
857     canvas->ShowText(tmpbuf);
858     canvas->EndText();
859     canvas->SetCharSpace(0);
860 
861     /* Print the subtitle. */
862     buf = GetStrParam(buf, tmpbuf, 255);
863     if (tmpbuf == NULL)
864         return;
865 
866     canvas->BeginText();
867     canvas->SetFontAndSize("Helvetica-Bold", PDF_CHAR_SIZE_TITLE1);
868     width = canvas->TextWidth(tmpbuf, &numchars);
869     double tmpl = canvas->Width() - width - 80;
870     canvas->MoveTextPos(tmpl, 470);
871 
872     canvas->ShowText(tmpbuf);
873     canvas->EndText();
874 
875     /* Print the version NO. */
876     buf = GetStrParam(buf, tmpbuf, 255);
877     if (tmpbuf == NULL)
878         return;
879 
880     canvas->BeginText();
881     canvas->SetFontAndSize("Helvetica-Bold", PDF_CHAR_SIZE_TITLE2);
882     width = canvas->TextWidth(tmpbuf, &numchars);
883 
884     tmpl = canvas->Width() - width - 80;
885     canvas->MoveTextPos(tmpl, 100);
886 
887     canvas->ShowText(tmpbuf);
888     canvas->EndText();
889 
890     /* Print the copyright */
891     GetStrParam(buf, tmpbuf, 255);
892     if (tmpbuf == NULL)
893         return;
894 
895     canvas->BeginText();
896     canvas->SetFontAndSize("Times-Bold", PDF_CHAR_SIZE_TITLE2);
897     width = canvas->TextWidth(tmpbuf, &numchars);
898     tmpl = canvas->Width() - width - 80;
899     canvas->MoveTextPos(tmpl, 80);
900 
901     canvas->ShowText(tmpbuf);
902     canvas->EndText();
903 
904 }
905 
906 void
SetFont(const char * name)907 DocMaker::SetFont(const char* name)
908 {
909     double fsize = fCanvas->FontSize();
910     const char* fname = fCanvas->FontName();
911 
912     if (strcmp(fname, name) != 0)
913         fCanvas->SetFontAndSize(name, fsize);
914     memset(fCurFont, 0x00, 64);
915     strncpy(fCurFont, name, 64 - 1);
916 }
917 
918 void
SetIndent(int level)919 DocMaker::SetIndent(int level)
920 {
921     if (level == 0)
922         fLeftMargin = LEFT_MARGIN;
923     else
924         fLeftMargin += level * 10;
925 }
926 
main(int argc,char ** argv)927 int main(int argc, char** argv)
928 {
929     FILE* infile;
930     const int BUF_LEN = 8192;
931     char buf[BUF_LEN];
932     char* filename = argv[1];
933     char* pdffname = argv[2];
934 
935     if (argc < 3) {
936         fprintf(stderr, "usage: DocMaker input-file-name output-file-name.\n");
937         return -1;
938     }
939     infile = fopen(filename, "r");
940     if (infile == NULL) {
941         fprintf(stderr, "error: file open failed.\n");
942         return -1;
943     }
944 
945     DocMaker* doc = NULL;
946     try {
947         doc = new DocMaker();
948     } catch (PdfException& e) {
949         fprintf(stderr, "%s\n", e.what());
950         fclose(infile);
951         return 1;
952     }
953 
954     try {
955         while (fgets(buf, BUF_LEN, infile) != NULL) {
956             unsigned int len = strlen(buf);
957             if (buf[len - 1] == 0x0d || buf[len - 1] == 0x0a) {
958                 buf[len - 1] = 0x00;
959                 len--;
960             }
961             if (buf[len - 1] == 0x0d || buf[len - 1] == 0x0a) {
962                 buf[len - 1] = 0x00;
963                 len --;
964             }
965             doc->IncCurLine();
966 
967             if (len >= 2) {
968 
969                 /* insert a brank line */
970                 if (memcmp(buf, "%;", 2) == 0)
971                     doc->ShowText("");
972                 else
973 
974                 /* insert a brank line (harf)*/
975                 if (memcmp(buf, "%:", 2) == 0)
976                     doc->IncLine();
977                 else
978 
979                 /* comment lines */
980                 if (memcmp(buf, "%#", 2) == 0)
981                     ;
982                 else
983 
984                 /* add front page */
985                 if (memcmp(buf, "%T", 2) == 0) {
986                     char* pbuf = buf + 2;
987                     doc->AddTitle(pbuf);
988                 } else
989 
990                 /* add section. */
991                 if (memcmp(buf, "%S", 2) == 0) {
992                     int level;
993                     char title[256];
994                     const char* pbuf = buf + 2;
995 
996                     pbuf = doc->GetStrParam(pbuf, title, 256);
997                     doc->GetIntParam(pbuf, &level);
998 
999                     try {
1000                         doc->AddSection(title, level);
1001                     } catch (PdfException& e) {
1002                         fprintf(stderr, e.what());
1003                         exit(2);
1004                     }
1005                 } else
1006 
1007                 /* show image. */
1008                 if (memcmp(buf, "%I", 2) == 0) {
1009                     char title[256];
1010                     char filename[256];
1011                     const char* pbuf = buf + 2;
1012 
1013                     pbuf = doc->GetStrParam(pbuf, title, 256);
1014                     pbuf = doc->GetStrParam(pbuf, filename, 256);
1015 
1016                     int width = 0;
1017                     int height = 0;
1018                     if (pbuf != NULL)
1019                         pbuf = doc->GetIntParam(pbuf, &width);
1020                     if (pbuf != NULL)
1021                         doc->GetIntParam(pbuf, &height);
1022 
1023                     doc->ShowImage(title, filename, width, height);
1024 
1025                 } else
1026 
1027                 /*  insert figure */
1028                 if (memcmp(buf, "%W", 2) == 0 && len > 8) {
1029                     char title[256];
1030                     char filename[256];
1031                     double height;
1032                     double width;
1033                     const char* pbuf = buf + 2;
1034 
1035                     pbuf = doc->GetStrParam(pbuf, title, 256);
1036                     pbuf = doc->GetStrParam(pbuf, filename, 256);
1037                     pbuf = doc->GetFloatParam(pbuf, &width);
1038                     pbuf = doc->GetFloatParam(pbuf, &height);
1039 
1040                     doc->ShowWMFImage(title, filename, width, height);
1041                 } else
1042 
1043                 /* change default font */
1044 
1045                 if (memcmp(buf, "%C", 2) == 0) {
1046                     char font_name[64];
1047                     const char* pbuf = buf + 2;
1048 
1049                     doc->GetStrParam(pbuf, font_name, 64);
1050                     doc->SetFont(font_name);
1051                 } else
1052 
1053                 /* set indent */
1054                 if (memcmp(buf, "%L", 2) == 0) {
1055                     int indent;
1056                     const char* pbuf = buf + 2;
1057 
1058                     doc->GetIntParam(pbuf, &indent);
1059                     doc->SetIndent(indent);
1060                 } else
1061 
1062                 /* label */
1063                 if (memcmp(buf, "%A", 2) == 0) {
1064                     int indent;
1065                     char label[128];
1066                     const char* pbuf = buf + 2;
1067 
1068                     pbuf = doc->GetIntParam(pbuf, &indent);
1069                     doc->GetStrParam(pbuf, label, 128);
1070                     doc->ShowLabel(label, indent);
1071                 } else
1072 
1073                 /* print text */
1074                     doc->ShowText(buf);
1075             }
1076         }
1077         doc->MakeIndex();
1078         doc->MakeOutline();
1079         doc->WriteToFile(pdffname);
1080     } catch (PdfException& e) {
1081         fprintf(stderr, "ERROR: %s line:%d.\n", e.what(), doc->CurLine());
1082         delete doc;
1083         fclose(infile);
1084         exit(1);
1085     }
1086 
1087     fclose(infile);
1088 
1089     delete doc;
1090 }
1091 
1092