source: trunk/Lucide/SOURCE/gui/lucidethumbs.cpp @ 198

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

workaround for hpfs386

File size: 11.0 KB
Line 
1/* ***** BEGIN LICENSE BLOCK *****
2 * Version: CDDL 1.0/LGPL 2.1
3 *
4 * The contents of this file are subject to the COMMON DEVELOPMENT AND
5 * DISTRIBUTION LICENSE (CDDL) Version 1.0 (the "License"); you may not use
6 * this file except in compliance with the License. You may obtain a copy of
7 * the License at http://www.sun.com/cddl/
8 *
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
13 *
14 * The Initial Developer of the Original Code is
15 * Eugene Romanenko, netlabs.org.
16 * Portions created by the Initial Developer are Copyright (C) 2006
17 * the Initial Developer. All Rights Reserved.
18 *
19 * Contributor(s):
20 *
21 * Alternatively, the contents of this file may be used under the terms of
22 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
23 * in which case the provisions of the LGPL are applicable instead of those
24 * above. If you wish to allow use of your version of this file only under the
25 * terms of the LGPL, and not to allow others to use your version of this file
26 * under the terms of the CDDL, indicate your decision by deleting the
27 * provisions above and replace them with the notice and other provisions
28 * required by the LGPL. If you do not delete the provisions above, a recipient
29 * may use your version of this file under the terms of any one of the CDDL
30 * or the LGPL.
31 *
32 * ***** END LICENSE BLOCK ***** */
33
34// interferes with os2medef.h
35#undef VERSION
36
37#define INCL_DOS
38#define INCL_MMIOOS2
39#define INCL_GPI
40#include <os2.h>
41#include <os2me.h>
42#include <fourcc.h>
43
44#include <stdlib.h>
45#include <string.h>
46#include <io.h>
47#include <fcntl.h>
48
49#include <ludoc.xh>
50
51#include "Lucide.h"
52#include "luutils.h"
53
54#define LUTHUMB_SIZE_X  256
55#define LUTHUMB_SIZE_Y  256
56static const char * const LUTHUMB_EA_NAME = "LUCIDE_THUMBNAIL";
57
58
59static bool loadMMIOFuncs();
60
61static HMODULE mmioHndl = NULLHANDLE;
62static bool mmioFuncsLoaded = loadMMIOFuncs();
63
64static void freeMmio()
65{
66    if ( mmioHndl != NULLHANDLE ) {
67        DosFreeModule( mmioHndl );
68    }
69}
70
71HMMIO  APIENTRY (*pMmioOpen)(PSZ,PMMIOINFO,ULONG);
72LONG   APIENTRY (*pMmioWrite)(HMMIO,PCHAR,LONG);
73ULONG  APIENTRY (*pMmioSetHeader)(HMMIO,PVOID,LONG,PLONG,ULONG,ULONG);
74USHORT APIENTRY (*pMmioClose)(HMMIO,USHORT);
75
76static bool loadMMIOFuncs()
77{
78    bool res = false;
79    do
80    {
81        if ( DosLoadModule( NULL, 0, "MMIO", &mmioHndl ) != 0 )
82            break;
83        if ( DosQueryProcAddr( mmioHndl, 0, "mmioOpen", (PFN *)&pMmioOpen ) != 0 )
84            break;
85        if ( DosQueryProcAddr( mmioHndl, 0, "mmioWrite", (PFN *)&pMmioWrite ) != 0 )
86            break;
87        if ( DosQueryProcAddr( mmioHndl, 0, "mmioSetHeader", (PFN *)&pMmioSetHeader ) != 0 )
88            break;
89        if ( DosQueryProcAddr( mmioHndl, 0, "mmioClose", (PFN *)&pMmioClose ) != 0 )
90            break;
91
92        res = true;
93    } while (0);
94
95    atexit( freeMmio );
96
97    return res;
98}
99
100
101static bool saveToImage( char *pszFileName, char *format,
102                         ULONG width, ULONG height, ULONG row_size,
103                         ULONG bpp, char* src_buf )
104{
105    bool              ret = false;
106    MMIOINFO          mmioinfoTarget;
107    HMMIO             hmmioTarget;
108    PBYTE             pbBuffer = NULL;
109    ULONG             cbBuffer,cbBitmapInfo, rl;
110    ULONG             rc;
111    MMIMAGEHEADER     mmImgHdr;
112    BITMAPINFO2       bmp;
113    FOURCC            saveas;
114
115    rl = ( ( bpp * width + 31 ) / 32 ) * 4;
116    cbBuffer = rl * height;
117
118    if ( !format ) {
119        return ret;
120    }
121
122    saveas = mmioFOURCC( format[0], format[1], format[2], format[3] );
123
124    // fill bmp
125    memset( &bmp, 0, sizeof( bmp ) );
126    bmp.cbFix         = sizeof( bmp );
127    bmp.cx            = width;
128    bmp.cy            = height;
129    bmp.cPlanes       = 1;
130    bmp.cBitCount     = bpp;
131    bmp.ulCompression = 0;
132    bmp.cbImage       = cbBuffer;
133
134    cbBitmapInfo = sizeof( bmp );
135
136    memset( &mmioinfoTarget, 0L, sizeof( MMIOINFO ) );
137    mmioinfoTarget.fccIOProc = saveas;
138    mmioinfoTarget.ulTranslate = MMIO_TRANSLATEHEADER | MMIO_TRANSLATEDATA;
139    hmmioTarget = pMmioOpen( pszFileName, &mmioinfoTarget, MMIO_CREATE | MMIO_WRITE |
140                                                        MMIO_DENYWRITE | MMIO_NOIDENTIFY );
141    if ( hmmioTarget )
142    {
143        ULONG ulBytesWritten;
144
145        memset( &mmImgHdr, 0, sizeof( MMIMAGEHEADER ) );
146        mmImgHdr.ulHeaderLength = sizeof(MMIMAGEHEADER);
147        mmImgHdr.ulContentType = MMIO_IMAGE_UNKNOWN;
148        mmImgHdr.ulMediaType = MMIO_MEDIATYPE_IMAGE;
149        mmImgHdr.mmXDIBHeader.XDIBHeaderPrefix.ulMemSize = cbBuffer;
150        mmImgHdr.mmXDIBHeader.XDIBHeaderPrefix.ulPelFormat = ( bpp < 24 ) ?
151                        mmioFOURCC('p','a','l','b') : mmioFOURCC('r','g','b','b');
152
153        mmImgHdr.mmXDIBHeader.XDIBHeaderPrefix.usTransType = 0;
154        mmImgHdr.mmXDIBHeader.XDIBHeaderPrefix.ulTransVal = 0;
155        memcpy( &mmImgHdr.mmXDIBHeader.BMPInfoHeader2, &bmp, cbBitmapInfo );
156        rc = pMmioSetHeader( hmmioTarget, &mmImgHdr, sizeof(MMIMAGEHEADER),
157                                    (PLONG)&ulBytesWritten, 0L, 0L);
158        if ( rc == MMIO_SUCCESS )
159        {
160            for ( int k=0; k < height; k++ )
161            {
162                char *line = src_buf + ( k * row_size );
163
164                ulBytesWritten = pMmioWrite( hmmioTarget, (char*)line, rl );
165
166                if ( ( ulBytesWritten == MMIO_ERROR ) || ( ulBytesWritten == 0 ) ) {
167                    break;
168                }
169            }
170
171            if ( ( ulBytesWritten != MMIO_ERROR ) && ( ulBytesWritten != 0 ) ) {
172                ret = true;
173            }
174        }
175
176        pMmioClose( hmmioTarget, 0L );
177    }
178
179    return ret;
180}
181
182static BOOL set_ea( const char *file_name, const char *ea_name,
183                    const char *ea_data, int ea_data_len )
184{
185    APIRET rc = 0;
186    EAOP2  op;
187
188    char *databuf = new char[(64*2*1024)+1024]; // twice 64K for EA data + 1024 for any case
189
190    op.fpGEA2List = (PGEA2LIST)0;
191    op.fpFEA2List = (PFEA2LIST)databuf;
192
193    int  ea_name_len = strlen( ea_name );
194    if ( ea_name_len > 255 ) {
195        delete databuf;
196        return FALSE;
197    }
198
199    char *databufp = databuf + sizeof( long );
200    *((long*)databufp) = 0; // Next field offset is zero - just one field here
201    databufp += sizeof(long);
202    *databufp++ = 0; // not critical
203    *databufp++ = (char)ea_name_len;
204    *((short*)databufp) = (short)ea_data_len;
205    databufp += sizeof(short);
206    memcpy( databufp, ea_name, ea_name_len+1 ); // with trailing zero
207    databufp += ea_name_len+1;
208    memcpy( databufp, ea_data, ea_data_len ); // with trailing zero
209    databufp += ea_data_len;
210
211    *((long*)databuf) = databufp-databuf; // Size of all that stuff
212
213    // HPFS386 workaround
214    // Save timestamp (setting EA drops timestamp on HPFS386)
215    APIRET qpirc = 0;
216    FILESTATUS3 fs = { 0 };
217    qpirc = DosQueryPathInfo( file_name, FIL_STANDARD, &fs, sizeof( fs ) );
218
219    // Write EA
220    rc = DosSetPathInfo( file_name, FIL_QUERYEASIZE, &op, sizeof(op), 0);
221    delete databuf;
222
223    // Restore timestamp
224    if ( qpirc == 0 ) {
225        DosSetPathInfo( file_name, FIL_STANDARD, &fs, sizeof( fs ), DSPI_WRTTHRU );
226    }
227
228    if ( rc != 0 ) {
229        return FALSE;
230    }
231
232    return TRUE;
233}
234
235bool Lucide::isThumbNeeded( const char *fn )
236{
237    // First, check if mmio is available
238    if ( !mmioFuncsLoaded ) {
239        return false;
240    }
241
242    // Second, check if file is writeable
243    if ( access( fn, W_OK ) != 0 ) {
244        // Isn't writable, do not waste time to render thumbnail
245        return false;
246    }
247
248    // Third, check if thumbnail EA already present
249    UCHAR    EnumBuf[200] = {0};      // Data Buffer
250    ULONG    ulEnumCnt    = 0;        // Count of entries to return
251    FEA2     *ptr         = NULL;     // Pointer to data items returned
252    ULONG    ulTemp       = 0;
253    APIRET   rc           = 0;
254
255    ulEnumCnt = (ULONG)-1; // Request as many attributes as will fit in buffer
256
257    rc = DosEnumAttribute( ENUMEA_REFTYPE_PATH, (PVOID)fn, 1L, &EnumBuf, sizeof( EnumBuf ),
258                           &ulEnumCnt, ENUMEA_LEVEL_NO_VALUE );
259
260    if ( rc != 0 ) {
261        // error look for EA names, return 'false' to prevent EA creation
262        // as if enum failed, creation may also fail
263        return false;
264    }
265
266    ptr = (FEA2 *)EnumBuf; // Mask the buffer pointer to an FEA2 structure
267
268    for ( ULONG i = 0; i < ulEnumCnt; i++ )
269    {
270        if ( strcmp( ptr->szName, LUTHUMB_EA_NAME ) == 0 ) {
271            return false; // Thumbnail already present
272        }
273        /// increment the ptr with the value in oNextEntryOffset
274        ulTemp = ptr->oNextEntryOffset + (ULONG)ptr;
275        ptr = (FEA2 *)ulTemp;
276    }
277    return true;
278}
279
280
281void Lucide::createThumbnail( LuDocument *doc )
282{
283    if ( !doc->isScalable( ev ) ) {
284        return;
285    }
286
287    // render first page
288    double width = 0, height = 0;
289    doc->getPageSize( ev, 0, &width, &height );
290    double zoom = __min( (double)LUTHUMB_SIZE_X / width, (double)LUTHUMB_SIZE_Y / height );
291    short bpp = doc->getBpp( ev );
292
293    long rx = width * zoom;
294    long ry = height * zoom;
295    LuPixbuf *pixbuf = new LuPixbuf( ev, rx, ry, bpp );
296    if ( !doc->renderPageToPixbuf( ev, 0, 0, 0, rx, ry, zoom, 0, pixbuf, NULL, NULL ) ) {
297        delete pixbuf;
298        return;
299    }
300
301    char *tmpgif = new char[ CCHMAXPATH ];
302    getTmpDir( tmpgif );
303    strcat( tmpgif, "LUTHUMB.TMP" );
304
305    bool saved = saveToImage( tmpgif, "GIFC", rx, ry, pixbuf->getRowSize( ev ),
306                              bpp * 8, (char *)pixbuf->getDataPtr( ev ) );
307    delete pixbuf;
308    if ( saved )
309    {
310        // If image file saved, read file content into
311        // thumbnailData buffer, to be able write it into EA
312        // when document will be closed
313        int h = open( tmpgif, O_RDONLY | O_BINARY | O_NOINHERIT );
314        if ( h != -1 )
315        {
316            long flen = filelength( h );
317            if ( flen > 0 )
318            {
319                thumbnailData = new char[ flen ];
320                thumbnailDataLen = flen;
321                if ( read( h, thumbnailData, flen ) != flen ) {
322                    delete thumbnailData;
323                    thumbnailData = NULL;
324                    thumbnailDataLen = 0;
325                }
326            }
327            close( h );
328        }
329    }
330    // if tmp file exist - delete it
331    if ( access( tmpgif, F_OK ) == 0 ) {
332        unlink( tmpgif );
333    }
334    delete tmpgif;
335}
336
337void Lucide::writeThumbnail( const char *fn )
338{
339    if ( ( thumbnailData == NULL ) || ( thumbnailDataLen == 0 ) ) {
340        return;
341    }
342
343    set_ea( fn, LUTHUMB_EA_NAME, (const char *)thumbnailData, thumbnailDataLen );
344    delete thumbnailData;
345    thumbnailData = NULL;
346    thumbnailDataLen = 0;
347}
348
Note: See TracBrowser for help on using the repository browser.