source: trunk/Lucide/SOURCE/plugins/lupoppler/lupoppler.cpp @ 144

Last change on this file since 144 was 144, checked in by Eugene Romanenko, 14 years ago

added version number of library used to plugin description

File size: 42.6 KB
Line 
1
2/*
3 *  This file was generated by the SOM Compiler.
4 *  Generated using:
5 *     SOM incremental update: 2.24
6 */
7
8/*
9 * Copyright (c) 2006, Eugene Romanenko, netlabs.org
10 *
11 *----------------------------------------------------------------------
12 * This file is part of poppler plugin for Lucide (lupoppler).
13 *
14 *  lupoppler is free software; you can redistribute it and/or modify
15 *  it under the terms of the GNU General Public License as published by
16 *  the Free Software Foundation; either version 2 of the License, or
17 *  (at your option) any later version.
18 *
19 *  lupoppler is distributed in the hope that it will be useful,
20 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
21 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22 *  GNU General Public License for more details.
23 *----------------------------------------------------------------------
24 */
25
26/*
27 *  This file was generated by the SOM Compiler and Emitter Framework.
28 *  Generated using template emitter:
29 *      SOM Emitter emitxtm: 2.23.1.9
30 */
31
32#ifndef SOM_Module_lupoppler_Source
33#define SOM_Module_lupoppler_Source
34#endif
35#define LuPopplerDocument_Class_Source
36
37#include "lupoppler.xih"
38
39#include <goo\GooString.h>
40#include <goo\GooList.h>
41#include <splash\SplashBitmap.h>
42#include <UGooString.h>
43#include <GlobalParams.h>
44#include <ErrorCodes.h>
45#include <PDFDoc.h>
46#include <SplashOutputDev.h>
47#include <TextOutputDev.h>
48#include <PSOutputDev.h>
49#include <FontInfo.h>
50#include <Outline.h>
51#include <UnicodeMap.h>
52#include <Gfx.h>
53#include <Link.h>
54
55#define INCL_DOS
56#include <os2.h>
57
58#include <vector>
59using namespace std;
60#include <time.h>
61#include "cpconv.h"
62
63typedef vector<LuRectangle> RectList;
64
65
66unsigned _System LibMain( unsigned hmod, unsigned termination )
67{
68    if ( termination ) {
69        /* DLL is detaching from process */
70    } else {
71        /* DLL is attaching to process */
72    }
73    return( 1 );
74}
75
76
77extern "C" LuDocument * _System createObject()
78{
79    return new LuPopplerDocument;
80}
81
82extern "C" char * _System getSupportedExtensions()
83{
84    return "PDF";
85}
86
87extern "C" char * _System getDescription()
88{
89    return "PDF plugin, based on poppler library v0.5.4";
90}
91
92
93class PopplerPage
94{
95    public:
96
97        Page *page;
98        TextOutputDev *text_dev;
99        Gfx *gfx;
100
101        PopplerPage();
102        ~PopplerPage();
103};
104
105PopplerPage::PopplerPage()
106{
107    page = NULL;
108    text_dev = NULL;
109    gfx = NULL;
110}
111
112PopplerPage::~PopplerPage()
113{
114    delete text_dev;
115    delete gfx;
116}
117
118
119class PopplerDocument
120{
121    public:
122
123        PDFDoc *doc;
124        SplashOutputDev *output_dev;
125        PopplerPage *pages;
126        char *text;
127        HMTX mutex;
128
129        PopplerDocument();
130        ~PopplerDocument();
131};
132
133PopplerDocument::PopplerDocument()
134{
135    doc        = NULL;
136    output_dev = NULL;
137    pages      = NULL;
138    text       = NULL;
139    mutex      = NULLHANDLE;
140    DosCreateMutexSem( NULL, &mutex, 0, FALSE );
141}
142
143PopplerDocument::~PopplerDocument()
144{
145    delete [] pages;
146    delete doc;
147    delete output_dev;
148    delete text;
149    DosCloseMutexSem( mutex );
150}
151
152
153static char *newstrdup( const char *s )
154{
155    if ( s == NULL ) {
156        return NULL;
157    }
158    char *temp = new char[ strlen( s ) + 1 ];
159    strcpy( temp, s );
160    return temp;
161}
162
163static char *somstrdup( const char *s )
164{
165    if ( s == NULL ) {
166        return NULL;
167    }
168    char *temp = (char *)SOMMalloc( strlen( s ) + 1 );
169    strcpy( temp, s );
170    return temp;
171}
172
173
174SOM_Scope short  SOMLINK getBpp(LuPopplerDocument *somSelf,  Environment *ev)
175{
176    return 3;
177}
178
179SOM_Scope boolean  SOMLINK isScalable(LuPopplerDocument *somSelf,
180                                       Environment *ev)
181{
182    return TRUE;
183}
184
185
186SOM_Scope boolean  SOMLINK isRotable(LuPopplerDocument *somSelf,
187                                      Environment *ev)
188{
189    return TRUE;
190}
191
192
193SOM_Scope long  SOMLINK getPageCount(LuPopplerDocument *somSelf,
194                                      Environment *ev)
195{
196    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
197    return ((PopplerDocument *)somThis->data)->doc->getNumPages();
198}
199
200
201SOM_Scope void  SOMLINK getPageSize(LuPopplerDocument *somSelf,
202                                    Environment *ev, long pagenum,
203                                    double* width, double* height)
204{
205    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
206
207    Page *page = ((PopplerDocument *)somThis->data)->pages[ pagenum ].page;
208
209    double page_width, page_height;
210    int rotate = page->getRotate();
211    if ( rotate == 90 || rotate == 270 ) {
212        page_height = page->getCropWidth();
213        page_width = page->getCropHeight();
214    } else {
215        page_width = page->getCropWidth();
216        page_height = page->getCropHeight();
217    }
218
219    if ( width != NULL ) {
220        *width = page_width;
221    }
222    if ( height != NULL ) {
223        *height = page_height;
224    }
225}
226
227
228static void copy_page_to_pixbuf( Environment *ev, SplashBitmap *bitmap, LuPixbuf *pixbuf )
229{
230    int splash_width, splash_height, splash_rowstride;
231    int pixbuf_rowstride, pixbuf_height, pixbuf_width;
232    int height, width, rowstride;
233    char *pixbuf_data, *dst, *src;
234
235    SplashColorPtr color_ptr = bitmap->getDataPtr();
236
237    splash_width = bitmap->getWidth();
238    splash_height = bitmap->getHeight();
239    splash_rowstride = bitmap->getRowSize();
240
241    //somPrintf( "splash_width: %d   splash_height: %d   splash_rowstride: %d\n",
242    //            splash_width, splash_height, splash_rowstride );
243
244    pixbuf_data = (char *)pixbuf->getDataPtr( ev );
245    pixbuf_width = pixbuf->getWidth( ev );
246    pixbuf_height = pixbuf->getHeight( ev );
247    pixbuf_rowstride = pixbuf->getRowSize( ev );
248
249    width = __min( splash_width, pixbuf_width );
250    height = __min( splash_height, pixbuf_height );
251    rowstride = __min( splash_rowstride, pixbuf_rowstride );
252
253    int i, j;
254    for ( i = 0, j = ( height - 1 ); i < height; i++, j-- )
255    {
256        dst = pixbuf_data + i * pixbuf_rowstride;
257        src = ((char *)color_ptr) + j * splash_rowstride;
258        memcpy( dst, src, rowstride );
259    }
260
261    // test
262    //memcpy( pixbuf_data, color_ptr, pixbuf->getDataLen( ev ) );
263}
264
265
266SOM_Scope void  SOMLINK renderPageToPixbuf(LuPopplerDocument *somSelf,
267                                            Environment *ev,
268                                           long pagenum, long src_x,
269                                           long src_y, long src_width,
270                                           long src_height, double scale,
271                                           long rotation, LuPixbuf* pixbuf)
272{
273    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
274    PopplerDocument *document = (PopplerDocument *)somThis->data;
275    Page *page = document->pages[ pagenum ].page;
276
277    if ( ( scale < 0.0 ) || ( pixbuf == NULL ) ) {
278        return;
279    }
280
281    DosRequestMutexSem( document->mutex, SEM_INDEFINITE_WAIT );
282
283    page->displaySlice( document->output_dev,
284                72.0 * scale, 72.0 * scale,
285                rotation,
286                gFalse, /* useMediaBox */
287                gTrue, /* Crop */
288                src_x, src_y,
289                src_width, src_height,
290                NULL, /* links */
291                document->doc->getCatalog() );
292
293    DosReleaseMutexSem( document->mutex );
294
295    copy_page_to_pixbuf( ev, document->output_dev->getBitmap(), pixbuf );
296}
297
298
299SOM_Scope boolean  SOMLINK isAsynchRenderingSupported(LuPopplerDocument *somSelf,
300                                                       Environment *ev)
301{
302    return TRUE;
303}
304
305
306struct asynchCallbackData
307{
308    Environment      *ev;
309    LuPixbuf         *pixbuf;
310    SplashOutputDev  *out;
311    void             *fndata;
312    _asynchCallbackFn fnd;
313    _asynchCallbackFn fna;
314    long              tmr;
315    bool              forceDraw;
316    long              delay;
317};
318
319static GBool abortCheckCbk( void *data )
320{
321    long now;
322    asynchCallbackData *cd = (asynchCallbackData *)data;
323    DosQuerySysInfo( QSV_MS_COUNT, QSV_MS_COUNT, &now, sizeof( long ) );
324    long dist = ( now - cd->tmr );
325    if ( ( dist > cd->delay ) || cd->forceDraw )
326    {
327        // Note: we use out->getBitmap() on each iteration instead
328        //       of remembering pointer to bitmap before call
329        //       page->displaySlice() because OutputDev may change
330        //       bitmap during page->displaySlice() processing.
331        copy_page_to_pixbuf( cd->ev, cd->out->getBitmap(), cd->pixbuf );
332        cd->fnd( cd->fndata );
333        cd->tmr = now;
334        cd->delay += 100;
335    }
336    return (GBool)cd->fna( cd->fndata );
337}
338
339SOM_Scope void  SOMLINK renderPageToPixbufAsynch(LuPopplerDocument *somSelf,
340                                                  Environment *ev,
341                                                 long pagenum,
342                                                 long src_x,
343                                                 long src_y,
344                                                 long src_width,
345                                                 long src_height,
346                                                 double scale,
347                                                 long rotation,
348                                                 LuPixbuf* pixbuf,
349                                                 LuDocument_asynchCallbackFn fnd,
350                                                 LuDocument_asynchCallbackFn fna,
351                                                 somToken fndata)
352{
353    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
354    PopplerDocument *document = (PopplerDocument *)somThis->data;
355    Page *page = document->pages[ pagenum ].page;
356
357    if ( ( scale < 0.0 ) || ( pixbuf == NULL ) ) {
358        return;
359    }
360
361    asynchCallbackData acd;
362    acd.ev        = ev;
363    acd.pixbuf    = pixbuf;
364    acd.out       = document->output_dev;
365    acd.fndata    = fndata;
366    acd.fnd       = (_asynchCallbackFn)fnd;
367    acd.fna       = (_asynchCallbackFn)fna;
368    acd.forceDraw = false;
369    acd.delay     = 200;
370    DosQuerySysInfo( QSV_MS_COUNT, QSV_MS_COUNT, &acd.tmr, sizeof( long ) );
371
372    DosRequestMutexSem( document->mutex, SEM_INDEFINITE_WAIT );
373
374    //somPrintf( "src_x: %d, src_y: %d, src_width: %d, src_height: %d\n",
375    //           src_x, src_y, src_width, src_height );
376
377    page->displaySlice( document->output_dev,
378                72.0 * scale, 72.0 * scale,
379                rotation,
380                gFalse, /* useMediaBox */
381                gTrue, /* Crop */
382                src_x, src_y,
383                src_width, src_height,
384                NULL, /* links */
385                document->doc->getCatalog(),
386                abortCheckCbk, &acd );
387    DosReleaseMutexSem( document->mutex );
388
389    acd.forceDraw = true;
390    abortCheckCbk( &acd );
391}
392
393static TextOutputDev *get_text_output_dev( PopplerPage *page,
394                                           PopplerDocument *document )
395{
396    if ( page->text_dev == NULL )
397    {
398        DosRequestMutexSem( document->mutex, SEM_INDEFINITE_WAIT );
399        page->text_dev = new TextOutputDev( NULL, gTrue, gFalse, gFalse );
400
401        page->gfx = page->page->createGfx(page->text_dev,
402                          72.0, 72.0, 0,
403                          gFalse, /* useMediaBox */
404                          gTrue, /* Crop */
405                          -1, -1, -1, -1,
406                          NULL, /* links */
407                          document->doc->getCatalog(),
408                          NULL, NULL, NULL, NULL);
409
410        page->page->display( page->gfx );
411        page->text_dev->endPage();
412        DosReleaseMutexSem( document->mutex );
413    }
414
415    return page->text_dev;
416}
417
418
419SOM_Scope LuDocument_LuRectSequence*  SOMLINK getSelectionRectangles(LuPopplerDocument *somSelf,
420                                                                    Environment *ev,
421                                                                   long pagenum,
422                                                                   LuRectangle* selection)
423{
424    LuDocument_LuRectSequence *rectangles = NULL;
425
426    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
427    PopplerDocument *document = (PopplerDocument *)somThis->data;
428    PopplerPage *page = &( document->pages[ pagenum ] );
429
430    TextOutputDev *text_dev = get_text_output_dev( page, document );
431
432    PDFRectangle poppler_selection;
433    poppler_selection.x1 = selection->x1;
434    poppler_selection.y1 = selection->y1;
435    poppler_selection.x2 = selection->x2;
436    poppler_selection.y2 = selection->y2;
437
438    GooList *list = text_dev->getSelectionRegion( &poppler_selection, 1.0 );
439    int len = list->getLength();
440
441    if ( len > 0 )
442    {
443        rectangles = (LuDocument_LuRectSequence *)SOMMalloc( sizeof( LuDocument_LuRectSequence ) );
444        rectangles->_maximum = len;
445        rectangles->_length = len;
446        rectangles->_buffer = (LuRectangle *)SOMMalloc( sizeof( LuRectangle ) * len );
447
448        for ( int i = 0; i < len; i++ )
449        {
450            PDFRectangle *selection_rect = (PDFRectangle *)list->get( i );
451            rectangles->_buffer[ i ].x1 = selection_rect->x1;
452            rectangles->_buffer[ i ].y1 = selection_rect->y1;
453            rectangles->_buffer[ i ].x2 = selection_rect->x2;
454            rectangles->_buffer[ i ].y2 = selection_rect->y2;
455            delete selection_rect;
456        }
457    }
458    delete list;
459
460    return rectangles;
461}
462
463
464SOM_Scope boolean  SOMLINK isHaveText(LuPopplerDocument *somSelf,
465                                      Environment *ev)
466{
467    return TRUE;
468}
469
470
471SOM_Scope string  SOMLINK getText(LuPopplerDocument *somSelf,
472                                   Environment *ev, long pagenum,
473                                  LuRectangle* selection)
474{
475    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
476
477    if ( selection == NULL ) {
478        return NULL;
479    }
480
481    PopplerDocument *document = (PopplerDocument *)somThis->data;
482    PopplerPage *page = &( document->pages[ pagenum ] );
483
484    TextOutputDev *text_dev = get_text_output_dev( page, document );
485
486    GooString *sel_text = new GooString;
487    char *result;
488    PDFRectangle pdf_selection;
489
490    pdf_selection.x1 = selection->x1;
491    pdf_selection.y1 = selection->y1;
492    pdf_selection.x2 = selection->x2;
493    pdf_selection.y2 = selection->y2;
494
495    DosRequestMutexSem( document->mutex, SEM_INDEFINITE_WAIT );
496    sel_text = text_dev->getSelectionText( &pdf_selection );
497
498    delete document->text;
499    document->text = newstrdup( sel_text->getCString() );
500    delete sel_text;
501    DosReleaseMutexSem( document->mutex );
502
503    return document->text;
504}
505
506
507SOM_Scope boolean  SOMLINK isHaveLinks(LuPopplerDocument *somSelf,
508                                        Environment *ev)
509{
510    return TRUE;
511}
512
513
514static long find_dest_page( PDFDoc *doc, LinkDest *link_dest )
515{
516    long page_num = 0;
517
518    if ( link_dest == NULL ) {
519        return page_num;
520    }
521
522    if ( link_dest->isPageRef() )
523    {
524        Ref page_ref = link_dest->getPageRef();
525        page_num = doc->findPage( page_ref.num, page_ref.gen ) - 1;
526    }
527    else {
528        page_num = link_dest->getPageNum() - 1;
529    }
530
531    return page_num;
532}
533
534static void build_goto_dest( PDFDoc *doc, LuLink *evlink, LinkGoTo *link )
535{
536    LinkDest *link_dest;
537    UGooString *named_dest;
538
539    if ( !link->isOk() ) {
540        return;
541    }
542
543    link_dest = link->getDest();
544    named_dest = link->getNamedDest();
545
546    if ( link_dest != NULL ) {
547        evlink->page = find_dest_page( doc, link_dest );
548    } else if ( named_dest != NULL ) {
549        link_dest = doc->findDest( named_dest );
550        evlink->page = find_dest_page( doc, link_dest );
551        delete link_dest;
552    } else {
553        evlink->page = 0;
554    }
555}
556
557static void build_link( PDFDoc *doc, LuLink *evlink,
558                        const char *title, LinkAction *link_action )
559{
560    evlink->title = somstrdup( title );
561    evlink->uri = NULL;
562    evlink->type = LU_LINK_TYPE_TITLE;
563    evlink->page = 0;
564
565    if ( link_action == NULL ) {
566        return;
567    }
568
569    switch ( link_action->getKind() )
570    {
571        case actionGoTo:
572            {
573                evlink->type = LU_LINK_TYPE_PAGE;
574                LinkGoTo *lgt = dynamic_cast <LinkGoTo *> (link_action);
575                build_goto_dest( doc, evlink, lgt );
576            }
577            break;
578
579        case actionURI:
580            {
581                evlink->type = LU_LINK_TYPE_EXTERNAL_URI;
582                LinkURI *lu = dynamic_cast <LinkURI *> (link_action);
583                char *uri = lu->getURI()->getCString();
584                if ( uri != NULL ) {
585                    evlink->uri = somstrdup( uri );
586                }
587            }
588            break;
589    }
590}
591
592SOM_Scope LuDocument_LuLinkMapSequence*  SOMLINK getLinkMapping(LuPopplerDocument *somSelf,
593                                                                 Environment *ev,
594                                                                long pagenum)
595{
596    LuDocument_LuLinkMapSequence *mapping = NULL;
597    mapping = (LuDocument_LuLinkMapSequence *)SOMMalloc( sizeof( LuDocument_LuLinkMapSequence ) );
598    mapping->_maximum = 0;
599    mapping->_length = 0;
600    mapping->_buffer = NULL;
601
602    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
603    PopplerDocument *document = (PopplerDocument *)somThis->data;
604    PopplerPage *page = &( document->pages[ pagenum ] );
605
606    Object obj;
607    Links *links = new Links( page->page->getAnnots( &obj ),
608                            document->doc->getCatalog()->getBaseURI() );
609    obj.free();
610
611    if ( links == NULL ) {  // No links, return empty LuLinkMapSequence
612        return mapping;
613    }
614
615    double height = 0;
616    getPageSize( somSelf, ev, pagenum, NULL, &height );
617
618    int len = links->getNumLinks();
619
620    mapping->_maximum = len;
621    mapping->_length = len;
622    if ( len != 0 ) {
623        mapping->_buffer = (LuLinkMapping *)SOMMalloc( sizeof( LuLinkMapping ) * len );
624    }
625
626    for ( int i = 0; i < len; i++ )
627    {
628        Link *link = links->getLink( i );
629        LinkAction *link_action = link->getAction();
630        build_link( document->doc, &(mapping->_buffer[ i ].link), NULL, link_action );
631
632        link->getRect( &(mapping->_buffer[ i ].area.x1),
633                       &(mapping->_buffer[ i ].area.y1),
634                       &(mapping->_buffer[ i ].area.x2),
635                       &(mapping->_buffer[ i ].area.y2) );
636
637        mapping->_buffer[ i ].area.x1 -= page->page->getCropBox()->x1;
638        mapping->_buffer[ i ].area.x2 -= page->page->getCropBox()->x1;
639        mapping->_buffer[ i ].area.y1 -= page->page->getCropBox()->y1;
640        mapping->_buffer[ i ].area.y2 -= page->page->getCropBox()->y1;
641
642        double y1 = mapping->_buffer[ i ].area.y1;
643        double y2 = mapping->_buffer[ i ].area.y2;
644        mapping->_buffer[ i ].area.y1 = height - y2;
645        mapping->_buffer[ i ].area.y2 = height - y1;
646    }
647
648    return mapping;
649}
650
651
652SOM_Scope boolean  SOMLINK isSaveable(LuPopplerDocument *somSelf,
653                                       Environment *ev)
654{
655    return TRUE;
656}
657
658
659SOM_Scope boolean  SOMLINK saveAs(LuPopplerDocument *somSelf,
660                                   Environment *ev, string filename)
661{
662    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
663    PopplerDocument *document = (PopplerDocument *)somThis->data;
664
665    boolean retval = FALSE;
666
667    if ( filename != NULL ) {
668        retval = document->doc->saveAs( new GooString( filename ) );
669    }
670
671    return retval;
672}
673
674
675SOM_Scope boolean  SOMLINK isPostScriptExportable(LuPopplerDocument *somSelf,
676                                           Environment *ev)
677{
678    return TRUE;
679}
680
681
682SOM_Scope boolean SOMLINK exportToPostScript(LuPopplerDocument *somSelf,
683                                    Environment *ev, string filename,
684                                    long first_page, long last_page,
685                                    double width, double height,
686                                    boolean* brkExport)
687{
688    if ( filename == NULL ) {
689        return FALSE;
690    }
691
692    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
693    PDFDoc *doc = ((PopplerDocument *)somThis->data)->doc;
694
695    PSOutputDev *out = new PSOutputDev( filename, doc->getXRef(), doc->getCatalog(),
696                                (first_page <= last_page) ? (first_page + 1) : (last_page + 1),
697                                (first_page <= last_page) ? (last_page + 1) : (first_page + 1),
698                                        psModePS, (int)width, (int)height,
699                                        gFalse, 0, 0, 0, 0, gFalse );
700
701    if ( !out->isOk() ) {
702        delete out;
703        return FALSE;
704    }
705
706    if ( *brkExport ) {
707        delete out;
708        return TRUE;
709    }
710
711    long pagestoprint = abs( last_page - first_page ) + 1;
712    long pg = first_page;
713    for ( long i = 0; (i < pagestoprint) && !(*brkExport); i++ ) {
714        doc->displayPage( out, pg + 1, 72.0, 72.0, 0, gFalse, gTrue, gFalse );
715        pg += ( first_page <= last_page ) ? 1 : -1;
716    }
717
718    delete out;
719    return TRUE;
720}
721
722
723SOM_Scope boolean  SOMLINK isHaveFontInfo(LuPopplerDocument *somSelf,
724                                           Environment *ev)
725{
726    return TRUE;
727}
728
729
730SOM_Scope LuDocument_LuFontInfoSequence*  SOMLINK getFontInfo(LuPopplerDocument *somSelf,
731                                                               Environment *ev)
732{
733    LuDocument_LuFontInfoSequence *fonts = NULL;
734
735    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
736    PopplerDocument *document = (PopplerDocument *)somThis->data;
737    PDFDoc *doc = document->doc;
738
739    DosRequestMutexSem( document->mutex, SEM_INDEFINITE_WAIT );
740    FontInfoScanner *scanner = new FontInfoScanner( doc );
741    GooList *items = scanner->scan( doc->getNumPages() );
742    delete scanner;
743    DosReleaseMutexSem( document->mutex );
744
745    if ( items == NULL ) {
746        return NULL;
747    }
748
749    int len = items->getLength();
750
751    if ( len == 0 ) {
752        delete items;
753        return NULL;
754    }
755
756    fonts = (LuDocument_LuFontInfoSequence *)SOMMalloc( sizeof( LuDocument_LuFontInfoSequence ) );
757    fonts->_maximum = len;
758    fonts->_length = len;
759    fonts->_buffer = (LuFontInfo *)SOMMalloc( sizeof( LuFontInfo ) * len );
760
761    for ( int i = 0; i < len; i++ )
762    {
763        fonts->_buffer[i].name = NULL;
764        fonts->_buffer[i].type = NULL;
765        fonts->_buffer[i].embedded = NULL;
766
767        FontInfo *info = (FontInfo *)items->get( i );
768
769        // name
770        GooString *gnm = info->getName();
771        if ( gnm != NULL )
772        {
773            char *nm = gnm->getCString();
774            if ( info->getSubset() && ( nm != NULL ) )
775            {
776                while ( *nm && ( *nm != '+' ) ) {
777                    nm++;
778                }
779                if ( *nm ) {
780                    nm++;
781                }
782            }
783            if ( nm != NULL ) {
784                if ( *nm ) {
785                    fonts->_buffer[i].name = somstrdup( nm );
786                }
787            }
788        }
789
790        // type
791        char *t = "Unknown font type";
792        switch ( info->getType() )
793        {
794            case FontInfo::Type1:        t = "Type 1";          break;
795            case FontInfo::Type1C:       t = "Type 1C";         break;
796            case FontInfo::Type3:        t = "Type 3";          break;
797            case FontInfo::TrueType:     t = "TrueType";        break;
798            case FontInfo::CIDType0:     t = "Type 1 (CID)";    break;
799            case FontInfo::CIDType0C:    t = "Type 1C (CID)";   break;
800            case FontInfo::CIDTrueType:  t = "TrueType (CID)";  break;
801        }
802        fonts->_buffer[i].type = somstrdup( t );
803
804        // embedded
805        if ( info->getEmbedded() ) {
806            if ( info->getSubset() ) {
807                fonts->_buffer[i].embedded = LU_FONTEMBED_EMBEDDED_SUBSET;
808            } else {
809                fonts->_buffer[i].embedded = LU_FONTEMBED_EMBEDDED;
810            }
811        } else {
812            fonts->_buffer[i].embedded = LU_FONTEMBED_NOT_EMBEDDED;
813        }
814    }
815
816    return fonts;
817}
818
819
820SOM_Scope boolean  SOMLINK isHaveIndex(LuPopplerDocument *somSelf,
821                                        Environment *ev)
822{
823    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
824    PDFDoc *doc = ((PopplerDocument *)somThis->data)->doc;
825
826    Outline *outline = doc->getOutline();
827    if ( outline == NULL ) {
828        return FALSE;
829    }
830
831    GooList *items = outline->getItems();
832    if ( items == NULL ) {
833        return FALSE;
834    }
835
836    return TRUE;
837}
838
839static char *unicode_to_char( Unicode *unicode, int len )
840{
841    static UnicodeMap *uMap = NULL;
842    if ( uMap == NULL )
843    {
844        GooString *enc = new GooString( "UTF-8" );
845        uMap = globalParams->getUnicodeMap( enc );
846        uMap->incRefCnt();
847        delete enc;
848    }
849
850    GooString gstr;
851    char buf[8]; // 8 is enough for mapping an unicode char to a string
852    int i, n;
853
854    for ( i = 0; i < len; ++i ) {
855        n = uMap->mapUnicode( unicode[i], buf, sizeof( buf ) );
856        gstr.append( buf, n );
857    }
858
859    return newstrdup( gstr.getCString() );
860}
861
862static char *newstrFromUTF8( const char *s )
863{
864    unsigned blen = strlen( s ) + 1;
865    char *b = new char[ blen ];
866    memset( b, 0, blen );
867    char *bsav = b;
868    const char *from = s;
869    unsigned flen = strlen( s );
870    cnvUTF8ToSys( &from, &flen, &b, &blen );
871    return bsav;
872}
873
874static void add_item( Environment *ev, PDFDoc *doc, LuIndexNode *n, GooList *items )
875{
876    if ( items == NULL ) {
877        return;
878    }
879
880    int len = items->getLength();
881
882    for ( int i = 0; i < len; i++ )
883    {
884        OutlineItem *item = (OutlineItem *)items->get( i );
885        LinkAction *link_action = item->getAction();
886        LuLink evlink;
887        char *t1 = unicode_to_char( item->getTitle(), item->getTitleLength() );
888        char *t2 = newstrFromUTF8( t1 );
889        build_link( doc, &evlink, t2, link_action );
890        delete t2;
891        delete t1;
892        LuIndexNode *cn = new LuIndexNode( ev, &evlink );
893        n->addChild( ev, cn );
894
895        item->open();
896        if ( item->hasKids() )
897        {
898            GooList *citems = item->getKids();
899            add_item( ev, doc, cn, citems );
900        }
901    }
902}
903
904SOM_Scope LuIndexNode*  SOMLINK getIndex(LuPopplerDocument *somSelf,
905                                          Environment *ev)
906{
907    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
908    PDFDoc *doc = ((PopplerDocument *)somThis->data)->doc;
909
910    Outline *outline = doc->getOutline();
911    if ( outline == NULL ) {
912        return NULL;
913    }
914
915    GooList *items = outline->getItems();
916    if ( items == NULL ) {
917        return NULL;
918    }
919
920    LuIndexNode *root = new LuIndexNode( ev, NULL );
921    add_item( ev, doc, root, items );
922
923    return root;
924}
925
926
927static bool has_unicode_marker( GooString *string )
928{
929    return ( ( (string->getChar(0) & 0xff) == 0xfe ) &&
930             ( (string->getChar(1) & 0xff) == 0xff ) );
931}
932
933// return SOMMalloc'ed string
934static char *propcnv( GooString *s )
935{
936    if ( has_unicode_marker( s ) )
937    {
938        unsigned blen = s->getLength() * 2;
939        char *b = (char *)SOMMalloc( blen );
940        memset( b, 0, blen );
941        char *bsav = b;
942        const char *from = s->getCString() + 2;
943        unsigned flen = s->getLength() - 2;
944        cnvUniBEToSys( &from, &flen, &b, &blen );
945        return bsav;
946    }
947
948    return somstrdup( s->getCString() );
949}
950
951static time_t propToDate( const char *date_string )
952{
953    int year, mon, day, hour, min, sec;
954    int scanned_items;
955
956    // See PDF Reference 1.3, Section 3.8.2 for PDF Date representation
957    if ( ( date_string[0] == 'D' ) && ( date_string[1] == ':' ) ) {
958        date_string += 2;
959    }
960
961    // FIXME only year is mandatory; parse optional timezone offset
962    scanned_items = sscanf( date_string, "%4d%2d%2d%2d%2d%2d",
963                            &year, &mon, &day, &hour, &min, &sec);
964
965    if ( scanned_items != 6 ) {
966        return (time_t)(-1);
967    }
968
969    // Workaround for y2k bug in Distiller 3, hoping that it won't
970    // be used after y2.2k
971    if ( ( year < 1930 ) && ( strlen( date_string ) > 14 ) )
972    {
973        int century, years_since_1900;
974        scanned_items = sscanf( date_string, "%2d%3d%2d%2d%2d%2d%2d",
975                &century, &years_since_1900, &mon, &day, &hour, &min, &sec );
976
977        if ( scanned_items != 7 ) {
978            return (time_t)(-1);
979        }
980
981        year = century * 100 + years_since_1900;
982    }
983
984    struct tm time = { 0 };
985    time.tm_year  = year - 1900;
986    time.tm_mon   = mon - 1;
987    time.tm_mday  = day;
988    time.tm_hour  = hour;
989    time.tm_min   = min;
990    time.tm_sec   = sec;
991    time.tm_wday  = -1;
992    time.tm_yday  = -1;
993    time.tm_isdst = -1; // 0 = DST off, 1 = DST on, -1 = don't know
994
995    return mktime( &time );
996}
997
998static long convPageMode( Catalog::PageMode pageMode )
999{
1000    switch ( pageMode )
1001    {
1002        case Catalog::pageModeThumbs:
1003            return LU_DOCUMENT_MODE_USE_THUMBS;
1004        case Catalog::pageModeFullScreen:
1005            return LU_DOCUMENT_MODE_FULL_SCREEN;
1006        case Catalog::pageModeOC:
1007            return LU_DOCUMENT_MODE_USE_OC;
1008        case Catalog::pageModeAttach:
1009            return LU_DOCUMENT_MODE_USE_ATTACHMENTS;
1010        case Catalog::pageModeNone:
1011            return LU_DOCUMENT_MODE_NONE;
1012    }
1013
1014    return -1;
1015}
1016
1017static long convLayout( Catalog::PageLayout pageLayout )
1018{
1019    switch ( pageLayout )
1020    {
1021        case Catalog::pageLayoutSinglePage:
1022            return LU_DOCUMENT_LAYOUT_SINGLE_PAGE;
1023        case Catalog::pageLayoutOneColumn:
1024            return LU_DOCUMENT_LAYOUT_ONE_COLUMN;
1025        case Catalog::pageLayoutTwoColumnLeft:
1026            return LU_DOCUMENT_LAYOUT_TWO_COLUMN_LEFT;
1027        case Catalog::pageLayoutTwoColumnRight:
1028            return LU_DOCUMENT_LAYOUT_TWO_COLUMN_RIGHT;
1029        case Catalog::pageLayoutTwoPageLeft:
1030            return LU_DOCUMENT_LAYOUT_TWO_PAGE_LEFT;
1031        case Catalog::pageLayoutTwoPageRight:
1032            return LU_DOCUMENT_LAYOUT_TWO_PAGE_RIGHT;
1033    }
1034    return -1;
1035}
1036
1037SOM_Scope LuDocumentInfo*  SOMLINK getDocumentInfo(LuPopplerDocument *somSelf,
1038                                                    Environment *ev)
1039{
1040    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
1041    PDFDoc *doc = ((PopplerDocument *)somThis->data)->doc;
1042
1043    LuDocumentInfo *info = (LuDocumentInfo *)SOMMalloc( sizeof( LuDocumentInfo ) );
1044    memset( info, 0, sizeof( LuDocumentInfo ) );
1045
1046    Object objdict;
1047    doc->getDocInfo( &objdict );
1048    if ( objdict.isDict() )
1049    {
1050        Dict *d = objdict.getDict();
1051        Object obj;
1052
1053        if ( d->lookup( "Title", &obj )->isString() ) {
1054            info->title = propcnv( obj.getString() );
1055            info->fields_mask |= LU_DOCUMENT_INFO_TITLE;
1056        }
1057        obj.free();
1058        if ( d->lookup( "Author", &obj )->isString() ) {
1059            info->author = propcnv( obj.getString() );
1060            info->fields_mask |= LU_DOCUMENT_INFO_AUTHOR;
1061        }
1062        obj.free();
1063        if ( d->lookup( "Subject", &obj )->isString() ) {
1064            info->subject = propcnv( obj.getString() );
1065            info->fields_mask |= LU_DOCUMENT_INFO_SUBJECT;
1066        }
1067        obj.free();
1068        if ( d->lookup( "Keywords", &obj )->isString() ) {
1069            info->keywords = propcnv( obj.getString() );
1070            info->fields_mask |= LU_DOCUMENT_INFO_KEYWORDS;
1071        }
1072        obj.free();
1073        if ( d->lookup( "Creator", &obj )->isString() ) {
1074            info->creator = propcnv( obj.getString() );
1075            info->fields_mask |= LU_DOCUMENT_INFO_CREATOR;
1076        }
1077        obj.free();
1078        if ( d->lookup( "Producer", &obj )->isString() ) {
1079            info->producer = propcnv( obj.getString() );
1080            info->fields_mask |= LU_DOCUMENT_INFO_PRODUCER;
1081        }
1082        obj.free();
1083        if ( d->lookup( "CreationDate", &obj )->isString() ) {
1084            char *d = propcnv( obj.getString() );
1085            info->creation_date = propToDate( d );
1086            if ( (long)info->creation_date != -1 ) {
1087                info->fields_mask |= LU_DOCUMENT_INFO_CREATION_DATE;
1088            }
1089            SOMFree( d );
1090        }
1091        obj.free();
1092        if ( d->lookup( "ModDate", &obj )->isString() ) {
1093            char *d = propcnv( obj.getString() );
1094            info->modified_date = propToDate( d );
1095            if ( (long)info->modified_date != -1 ) {
1096                info->fields_mask |= LU_DOCUMENT_INFO_MOD_DATE;
1097            }
1098            SOMFree( d );
1099        }
1100        obj.free();
1101    }
1102
1103    char *format = (char *)SOMMalloc( 16 );
1104    snprintf( format, 16, "PDF-%.2f", doc->getPDFVersion() );
1105    info->format = format;
1106    info->fields_mask |= LU_DOCUMENT_INFO_FORMAT;
1107
1108    info->linearized = doc->isLinearized();
1109    info->fields_mask |= LU_DOCUMENT_INFO_LINEARIZED;
1110
1111    Catalog *catalog = doc->getCatalog();
1112
1113    if ( ( catalog != NULL ) && catalog->isOk() )
1114    {
1115        info->layout = convLayout( catalog->getPageLayout() );
1116        if ( info->layout != -1 ) {
1117            info->fields_mask |= LU_DOCUMENT_INFO_LAYOUT;
1118        }
1119
1120        info->mode = convPageMode( catalog->getPageMode() );
1121        if ( info->mode != -1 ) {
1122            info->fields_mask |= LU_DOCUMENT_INFO_START_MODE;
1123        }
1124    }
1125
1126    info->fields_mask |= LU_DOCUMENT_INFO_PERMISSIONS;
1127    if ( doc->okToPrint() ) {
1128        info->permissions |= LU_DOCUMENT_PERMISSIONS_OK_TO_PRINT;
1129    }
1130    if ( doc->okToChange() ) {
1131        info->permissions |= LU_DOCUMENT_PERMISSIONS_OK_TO_MODIFY;
1132    }
1133    if ( doc->okToCopy() ) {
1134        info->permissions |= LU_DOCUMENT_PERMISSIONS_OK_TO_COPY;
1135    }
1136    if ( doc->okToAddNotes() ) {
1137        info->permissions |= LU_DOCUMENT_PERMISSIONS_OK_TO_ADD_NOTES;
1138    }
1139
1140    info->n_pages = doc->getNumPages();
1141    info->fields_mask |= LU_DOCUMENT_INFO_N_PAGES;
1142
1143    return info;
1144}
1145
1146
1147SOM_Scope boolean  SOMLINK getThumbnailSize(LuPopplerDocument *somSelf,
1148                                             Environment *ev,
1149                                            long pagenum,
1150                                            short suggested_width,
1151                                            short* width, short* height)
1152{
1153    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
1154    Page *page = ((PopplerDocument *)somThis->data)->pages[ pagenum ].page;
1155
1156    Object thumb;
1157    Dict *dict;
1158    boolean retval = FALSE;
1159
1160    page->getThumb( &thumb );
1161    if ( thumb.isNull() )
1162    {
1163        thumb.free();
1164        return FALSE;
1165    }
1166
1167    dict = thumb.streamGetDict();
1168
1169    // Theoretically, this could succeed and you would still fail when
1170    // loading the thumb
1171    int w = 0, h = 0;
1172    if ( dict->lookupInt( "Width", "W", &w ) && dict->lookupInt( "Height", "H", &h ) )
1173    {
1174        if ( width != NULL ) {
1175            *width = w;
1176        }
1177        if ( height != NULL ) {
1178            *height = h;
1179        }
1180
1181        retval = TRUE;
1182    }
1183
1184    thumb.free();
1185
1186    return retval;
1187}
1188
1189SOM_Scope LuPixbuf*  SOMLINK getThumbnail(LuPopplerDocument *somSelf,
1190                                           Environment *ev, long pagenum,
1191                                          short suggested_width)
1192{
1193    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
1194    Page *page = ((PopplerDocument *)somThis->data)->pages[ pagenum ].page;
1195
1196    unsigned char *data;
1197    int width, height, rowstride;
1198
1199    if ( !page->loadThumb( &data, &width, &height, &rowstride ) ) {
1200        return NULL;
1201    }
1202
1203    short bpp = getBpp( somSelf, ev );
1204    LuPixbuf *pixbuf = new LuPixbuf( ev, width, height, bpp );
1205    char *pixbuf_data = (char *)pixbuf->getDataPtr( ev );
1206    int pixbuf_rowstride = pixbuf->getRowSize( ev );
1207    char *src, *dst;
1208    int i, j;
1209    for ( i = 0, j = ( height - 1 ); i < height; i++, j-- )
1210    {
1211        src = data + ( j * rowstride );
1212        dst = pixbuf_data + (i * pixbuf_rowstride);
1213        for ( int k = 0; k < pixbuf_rowstride; k += bpp )
1214        {
1215            dst[ k ]     = src[ k + 2 ];
1216            dst[ k + 1 ] = src[ k + 1 ];
1217            dst[ k + 2 ] = src[ k ];
1218        }
1219    }
1220    gfree( data );
1221
1222    return pixbuf;
1223}
1224
1225
1226SOM_Scope LuDocument_LuRectSequence*  SOMLINK searchText(LuPopplerDocument *somSelf,
1227                                                          Environment *ev,
1228                                                         long pagenum,
1229                                                         string text,
1230                                                         boolean caseSensitive)
1231{
1232    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData(somSelf);
1233    PopplerDocument *document = (PopplerDocument *)somThis->data;
1234    Page *page = document->pages[ pagenum ].page;
1235
1236    DosRequestMutexSem( document->mutex, SEM_INDEFINITE_WAIT );
1237    TextOutputDev *output_dev = new TextOutputDev( NULL, gTrue, gFalse, gFalse );
1238    page->display( output_dev, 72, 72, 0, gFalse,
1239                   gTrue, NULL, document->doc->getCatalog() );
1240    DosReleaseMutexSem( document->mutex );
1241
1242
1243    // Convert string from system encoding to UCS-4
1244    // first, convert to UCS-2
1245    unsigned text_len = strlen( text );
1246    unsigned text_len_sav = text_len;
1247    unsigned ucs2_len = ( text_len + 1 ) * 2;
1248    char *ucs2 = new char[ ucs2_len ];
1249    memset( ucs2, 0, ucs2_len );
1250    char *ucs2sav = ucs2;
1251    cnvSysToUCS2( (const char **)&text, &text_len, &ucs2, &ucs2_len );
1252    // second, convert UCS-2 to UCS-4
1253    short *uucs2 = (short *)ucs2sav;
1254    unsigned ucs4_len = ( text_len_sav + 1 ) * 2;
1255    unsigned *ucs4 = new unsigned[ ucs4_len ];
1256    memset( ucs4, 0, ucs4_len * sizeof( unsigned ) );
1257    int real_ucs4_len = 0;
1258    for ( real_ucs4_len = 0; *uucs2; real_ucs4_len++ ) {
1259        ucs4[ real_ucs4_len ] = *uucs2++;
1260    }
1261    delete ucs2sav;
1262    // conversion end
1263
1264    RectList *rl = new RectList;
1265    double xMin, yMin, xMax, yMax;
1266    xMin = 0;
1267    yMin = 0;
1268    while ( output_dev->findText( ucs4, real_ucs4_len,
1269                   gFalse, gTrue, // startAtTop, stopAtBottom
1270                   gTrue, gFalse, // startAtLast, stopAtLast
1271                   caseSensitive, gFalse, // caseSensitive, backwards
1272                   &xMin, &yMin, &xMax, &yMax ) )
1273    {
1274        LuRectangle r;
1275        r.x1 = xMin;
1276        r.y1 = yMin;
1277        r.x2 = xMax;
1278        r.y2 = yMax;
1279        rl->push_back( r );
1280    }
1281    delete ucs4;
1282    delete output_dev;
1283
1284    LuDocument_LuRectSequence *rectangles = NULL;
1285    int len = rl->size();
1286    if ( len > 0 )
1287    {
1288        rectangles = (LuDocument_LuRectSequence *)SOMMalloc( sizeof( LuDocument_LuRectSequence ) );
1289        rectangles->_maximum = len;
1290        rectangles->_length = len;
1291        rectangles->_buffer = (LuRectangle *)SOMMalloc( sizeof( LuRectangle ) * len );
1292
1293        for ( int i = 0; i < len; i++ )
1294        {
1295            rectangles->_buffer[ i ].x1 = (*rl)[i].x1;
1296            rectangles->_buffer[ i ].y1 = (*rl)[i].y1;
1297            rectangles->_buffer[ i ].x2 = (*rl)[i].x2;
1298            rectangles->_buffer[ i ].y2 = (*rl)[i].y2;
1299        }
1300    }
1301    delete rl;
1302
1303    return rectangles;
1304}
1305
1306
1307SOM_Scope boolean  SOMLINK isFixedImage(LuPopplerDocument *somSelf,
1308                                         Environment *ev)
1309{
1310    return FALSE;
1311}
1312
1313
1314SOM_Scope void SOMLINK somDefaultInit(LuPopplerDocument *somSelf,
1315                                      som3InitCtrl* ctrl)
1316{
1317    // generated section - do not modify
1318    LuPopplerDocumentData *somThis;
1319    somInitCtrl globalCtrl;
1320    somBooleanVector myMask;
1321    LuPopplerDocument_BeginInitializer_somDefaultInit;
1322    LuPopplerDocument_Init_LuDocument_somDefaultInit(somSelf, ctrl);
1323    // end of generated section
1324
1325    // local LuPopplerDocument initialization code
1326    PopplerDocument *d = new PopplerDocument;
1327    somThis->data = d;
1328}
1329
1330
1331static void set_error( char **error, const char *fmt, ... )
1332{
1333    if ( error == NULL ) {
1334        return;
1335    }
1336
1337    va_list argptr;
1338    va_start( argptr, fmt );
1339    char *msg = new char[ 1000 ];
1340    vsnprintf( msg, 1000, fmt, argptr );
1341    *error = somstrdup( msg );
1342    delete msg;
1343}
1344
1345
1346SOM_Scope boolean  SOMLINK loadFile(LuPopplerDocument *somSelf,
1347                                    Environment *ev, string filename,
1348                                    string password, string* error)
1349{
1350    LuPopplerDocumentData *somThis = LuPopplerDocumentGetData( somSelf );
1351
1352    PDFDoc *newDoc;
1353    GooString *filename_g;
1354    GooString *password_g;
1355    int err;
1356
1357    if ( !globalParams ) {
1358        globalParams = new GlobalParams( NULL );
1359    }
1360
1361    filename_g = new GooString(filename);
1362
1363    password_g = NULL;
1364    if (password != NULL) {
1365        password_g = new GooString(password);
1366    }
1367
1368    newDoc = new PDFDoc(filename_g, password_g, password_g);
1369    if (password_g) {
1370        delete password_g;
1371    }
1372
1373    if (!newDoc->isOk()) {
1374        err = newDoc->getErrorCode();
1375        delete newDoc;
1376
1377        if (err == errEncrypted) {
1378            set_error(error, "Document is encrypted.");
1379        } else {
1380            set_error(error, "Failed to load document (error %d) '%s'\n", err, filename );
1381        }
1382
1383        return FALSE;
1384    }
1385
1386    PopplerDocument *document = (PopplerDocument *)somThis->data;
1387
1388    document->doc = newDoc;
1389    SplashColor white;
1390    white[0] = 255;
1391    white[1] = 255;
1392    white[2] = 255;
1393    document->output_dev = new SplashOutputDev( splashModeBGR8, 4, gFalse, white );
1394    document->output_dev->startDoc( document->doc->getXRef() );
1395
1396    long numpages = document->doc->getNumPages();
1397    document->pages = new PopplerPage[ numpages ];
1398    for ( long pagenum = 0; pagenum < numpages; pagenum++ ) {
1399        document->pages[ pagenum ].page =
1400            document->doc->getCatalog()->getPage( pagenum + 1 );
1401    }
1402
1403    return TRUE;
1404}
1405
1406
1407SOM_Scope void SOMLINK somDestruct(LuPopplerDocument *somSelf,
1408                                   octet doFree, som3DestructCtrl* ctrl)
1409{
1410    LuPopplerDocumentData *somThis;
1411    somDestructCtrl globalCtrl;
1412    somBooleanVector myMask;
1413    LuPopplerDocument_BeginDestructor;
1414
1415    // local LuPopplerDocument deinitialization code
1416    PopplerDocument *document = (PopplerDocument *)somThis->data;
1417    delete document;
1418    // end of local LuPopplerDocument deinitialization code
1419
1420    LuPopplerDocument_EndDestructor;
1421}
1422
1423
Note: See TracBrowser for help on using the repository browser.