]> git.sesse.net Git - vlc/blob - src/misc/rsc_files.c
* Header cleaning: filled all empty authors fields, added CVS $Id stuff.
[vlc] / src / misc / rsc_files.c
1 /*****************************************************************************
2  * rsc_files.c: resources files manipulation functions
3  * This library describe a general format used to store 'resources'. Resources
4  * can be anything, including pictures, audio streams, and so on.
5  *****************************************************************************
6  * Copyright (C) 1999, 2000 VideoLAN
7  * $Id: rsc_files.c,v 1.9 2001/03/21 13:42:34 sam Exp $
8  *
9  * Authors: Vincent Seguin <seguin@via.ecp.fr>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
24  *****************************************************************************/
25
26 /*****************************************************************************
27  * Format of a resource file:
28  *  offset      type        meaning
29  *  0           char[2]     "RF" (magic number)
30  *  2           char[2]     "VL" (minor magic number, ignored)
31  *  4           u16         i_type: resource file type. This is to allow
32  *                          different versions of the resources types constants.
33  *  6           u16         i_size: number of entries in the resources table.
34  * {
35  *  +0          char[32]    resource name (ASCIIZ or ASCII[32])
36  *  +32         u16         resource type
37  *  +34         u64         data offset in bytes, from beginning of file
38  *  +42         u64         data size in bytes
39  * } * i_size
40  *****************************************************************************/
41
42 /*****************************************************************************
43  * Preamble
44  *****************************************************************************/
45 #include "defs.h"
46
47 #include <errno.h>                                                  /* errno */
48 #include <fcntl.h>                                                 /* open() */
49 #include <stdlib.h>                                                /* free() */
50 #include <string.h>                                /* strerror(), strncopy() */
51 #include <unistd.h>                     /* read(), close(), lseek(), write() */
52
53 #include "config.h"
54 #include "common.h"
55 #include "mtime.h"
56
57 #include "rsc_files.h"
58
59 #include "intf_msg.h"
60
61 /*****************************************************************************
62  * CreateResourceFile: create a new resource file
63  *****************************************************************************
64  * Creates a new resource file. The file is opened read/write and erased if
65  * it already exists.
66  *****************************************************************************
67  * Messages type: rsc, major code 101
68  *****************************************************************************/
69 resource_file_t *CreateResourceFile( char *psz_filename, int i_type, int i_size,
70                                      int i_mode )
71 {
72     resource_file_t *   p_file;                            /* new descriptor */
73     int                 i_index;                           /* resource index */
74
75     /* Create descriptor and tables */
76     p_file = malloc( sizeof(resource_file_t) );
77     if( p_file == NULL )
78     {
79         intf_ErrMsg("rsc error 101-1: %s", strerror(errno));
80         return( NULL );
81     }
82     p_file->p_resource = malloc( sizeof(resource_descriptor_t) * i_size );
83     if( p_file->p_resource == NULL )
84     {
85         intf_ErrMsg("rsc error 101-2: %s", strerror(errno));
86         free( p_file );
87         return( NULL );
88     }
89
90     /* Open file */
91     p_file->i_file = open( psz_filename, O_CREAT | O_RDWR, i_mode );
92     if( p_file->i_file == -1 )                                      /* error */
93     {
94         intf_ErrMsg("rsc error 101-3: %s: %s", psz_filename, strerror(errno) );
95         free( p_file->p_resource );
96         free( p_file );
97     }
98
99     /* Initialize tables */
100     p_file->i_type = i_type;
101     p_file->i_size = i_size;
102     p_file->b_read_only = 0;
103     for( i_index = 0; i_index < i_size; i_index++ )
104     {
105         p_file->p_resource[i_index].i_type = EMPTY_RESOURCE;
106     }
107
108     return( p_file );
109 }
110
111 /*****************************************************************************
112  * OpenResourceFile: open an existing resource file read-only
113  *****************************************************************************
114  * Open an existing resource file. i_flags should be O_RDONLY or O_RDWR. An
115  * error will occurs if the file does not exists.
116  *****************************************************************************
117  * Messages type: rsc, major code 102
118  *****************************************************************************/
119 resource_file_t *OpenResourceFile( char *psz_filename, int i_type, int i_flags )
120 {
121     resource_file_t *   p_file;                            /* new descriptor */
122     int                 i_index;                           /* resource index */
123     byte_t              p_buffer[50];                              /* buffer */
124
125     /* Create descriptor and tables */
126     p_file = malloc( sizeof(resource_file_t) );
127     if( p_file == NULL )
128     {
129         intf_ErrMsg("rsc error 102-1: %s", strerror(errno));
130         return( NULL );
131     }
132
133     /* Open file */
134     p_file->i_file = open( psz_filename, i_flags );
135     if( p_file->i_file == -1 )                                      /* error */
136     {
137         intf_ErrMsg("rsc error 102-2: %s: %s", psz_filename, strerror(errno) );
138         free( p_file );
139         return( NULL );
140     }
141
142     /* Read header */
143     if( read( p_file->i_file, p_buffer, 8 ) != 8)
144     {
145         intf_ErrMsg("rsc error 102-3: %s: unexpected end of file (not a resource file ?)");
146         close( p_file->i_file );
147         free( p_file);
148         return( NULL );
149     }
150     if( (p_buffer[0] != 'R') || (p_buffer[0] != 'F') || (*(u16 *)(p_buffer + 4) != i_type) )
151     {
152         intf_ErrMsg("rsc error 102-4: %s is not a valid resource file or has incorrect type", psz_filename);
153         close( p_file->i_file );
154         free( p_file );
155         return( NULL );
156     }
157     p_file->i_type = i_type;
158     p_file->i_size = *(u16 *)(p_buffer + 6);
159     intf_DbgMsg("rsc debug 102-1: %s opened, %d resources", psz_filename, p_file->i_size);
160
161     /* Allocate tables */
162     p_file->p_resource = malloc( sizeof(resource_descriptor_t) * p_file->i_size );
163     if( p_file->p_resource == NULL )
164     {
165         intf_ErrMsg("rsc error 102-5: %s", strerror(errno));
166         close( p_file->i_file );
167         free( p_file );
168         return( NULL );
169     }
170
171     /* Initialize table */
172     p_file->b_up_to_date = 1;
173     p_file->b_read_only = ( i_flags & O_RDWR ) ? 0 : 1;
174     for( i_index = 0; i_index < p_file->i_size; i_index++ )
175     {
176         if( read( p_file->i_file, p_buffer, 50 ) != 50 )
177         {
178             intf_ErrMsg("rsc error 102-6: %s: unexpected end of file", psz_filename);
179             close( p_file->i_file );
180             free( p_file->p_resource );
181             free( p_file );
182             return( NULL );
183         }
184         memcpy( p_file->p_resource[i_index].psz_name, p_buffer, 32 );
185         p_file->p_resource[i_index].psz_name[RESOURCE_MAX_NAME] = '\0';
186         p_file->p_resource[i_index].i_type =    *(u16 *)(p_buffer + 32 );
187         p_file->p_resource[i_index].i_offset =  *(u64 *)(p_buffer + 34 );
188         p_file->p_resource[i_index].i_size =    *(u64 *)(p_buffer + 42 );
189     }
190
191     return( p_file );
192 }
193
194 /*****************************************************************************
195  * UpdateResourceFile: write the resources table in a resource file
196  *****************************************************************************
197  * This function writes resources table in the resource file. This is
198  * automatically done when the file is closed, but can also be done manually.
199  *****************************************************************************
200  * Messages type: rsc, major code 103
201  *****************************************************************************/
202 int UpdateResourceFile( resource_file_t *p_file )
203 {
204     byte_t      p_buffer[50];                                      /* buffer */
205     int         i_index;                                   /* resource index */
206
207 #ifdef DEBUG
208     if( p_file->b_read_only )
209     {
210         intf_DbgMsg("rsc debug 103-1: can't update a read-only file");
211         return( -1 );
212     }
213 #endif
214
215     /* Seek beginning of file */
216     if( lseek( p_file->i_file, 0, SEEK_SET ) )
217     {
218         intf_ErrMsg("rsc error 103-1: %s", strerror(errno));
219         return( -2 );
220     }
221
222     /* Write header */
223     p_buffer[0] =               'R';
224     p_buffer[1] =               'F';
225     p_buffer[2] =               'V';
226     p_buffer[3] =               'L';
227     *(u16 *)(p_buffer + 4) =    p_file->i_type;
228     *(u16 *)(p_buffer + 6) =    p_file->i_size;
229     if( write( p_file->i_file, p_buffer, 8 ) != 8 )
230     {
231         intf_ErrMsg("rsc error 103-2: %s", strerror(errno));
232         return( -3 );
233     }
234
235     /* Write resources table */
236     for( i_index = 0; i_index < p_file->i_size; i_index++ )
237     {
238         memcpy( p_buffer, p_file->p_resource[i_index].psz_name, 32 );
239         *(u16 *)(p_buffer + 32) =   p_file->p_resource[i_index].i_type;
240         *(u64 *)(p_buffer + 34) =   p_file->p_resource[i_index].i_offset;
241         *(u64 *)(p_buffer + 42) =   p_file->p_resource[i_index].i_size;
242         if( write( p_file->i_file, p_buffer, 8 ) != 8 )
243         {
244             intf_ErrMsg("rsc error 103-3: %s", strerror(errno));
245             return( -4 );
246         }
247     }
248
249     /* Mark file as up to date */
250     p_file->b_up_to_date = 1;
251
252     return( 0 );
253 }
254
255 /*****************************************************************************
256  * CloseResourceFile: close a resource file
257  *****************************************************************************
258  * Updates the resources table if required, and close the file. It returns non
259  * 0 in case of error.
260  *****************************************************************************
261  * Messages type: rsc, major code 104
262  *****************************************************************************/
263 int CloseResourceFile( resource_file_t *p_file )
264 {
265     /* Update table */
266     if( !p_file->b_up_to_date && ( UpdateResourceFile( p_file ) < 0 ) )
267     {
268         return( -1 );
269     }
270
271     /* Close and destroy descriptor */
272     if( close( p_file->i_file ) )
273     {
274         intf_ErrMsg("rsc error 104-1: %s", strerror(errno));
275         return( -2 );
276     }
277     free( p_file->p_resource );
278     free( p_file );
279     return( 0 );
280 }
281
282 /*****************************************************************************
283  * SeekResource: seek a resource in a resource file
284  *****************************************************************************
285  * Look for a resource in file and place the "reading head" at the beginning of
286  * the resource data.
287  * In case of success, the resource number is returned. Else, a negative number
288  * is returned.
289  *****************************************************************************
290  * Messages type: rsc, major code 105
291  *****************************************************************************/
292 int SeekResource( resource_file_t *p_file, char *psz_name, int i_type )
293 {
294     int     i_index;                                       /* resource index */
295
296     /* Look for resource in table */
297     for( i_index = 0;
298          (i_index < p_file->i_size)
299              && ((i_type != p_file->p_resource[i_index].i_type )
300                  || strcmp(psz_name, p_file->p_resource[i_index].psz_name));
301          i_index++ )
302     {
303         ;
304     }
305     if( i_index == p_file->i_size )
306     {
307         intf_ErrMsg("rsc error 105-1: unknown resource %s.%d", psz_name, i_type);
308         return( -1 );
309     }
310
311     /* Seek */
312     if( lseek( p_file->i_file, p_file->p_resource[i_index].i_offset, SEEK_SET ) )
313     {
314         intf_ErrMsg("rsc error 105-2: can not reach %s.%d: %s", psz_name,
315                     i_type, strerror(errno));
316         return( -2 );
317     }
318
319     return( i_index );
320 }
321
322 /*****************************************************************************
323  * ReadResource: read a resource
324  *****************************************************************************
325  * Read a resource from a file. The function returns a negative value in case
326  * of error, and 0 in case of success.
327  *****************************************************************************
328  * Messages type: rsc, major code 106
329  *****************************************************************************/
330 int ReadResource( resource_file_t *p_file, char *psz_name, int i_type,
331                   size_t max_size, byte_t *p_data )
332 {
333     int i_index;                                           /* resource index */
334
335     /* Seek resource */
336     i_index = SeekResource( p_file, psz_name, i_type );
337     if( i_index < 0 )
338     {
339         return( -1 );
340     }
341
342     /* Check if buffer is large enough */
343     if( max_size < p_file->p_resource[i_index].i_size )
344     {
345         intf_ErrMsg("rsc error 106-1: buffer is too small");
346         return( -2 );
347     }
348
349     /* Read data */
350     if( read( p_file->i_file, p_data, p_file->p_resource[i_index].i_size )
351         != p_file->p_resource[i_index].i_size )
352     {
353         intf_ErrMsg("rsc error 106-2: can not read %s.%d: %s",
354                     p_file->p_resource[i_index].psz_name,
355                     p_file->p_resource[i_index].i_type,
356                     strerror(errno));
357         return( -3 );
358     }
359
360     return( 0 );
361 }
362
363 /*****************************************************************************
364  * WriteResource: write a resource
365  *****************************************************************************
366  * Append a resource at the end of the file. It returns non 0 on error.
367  *****************************************************************************
368  * Messages type: rsc, major code 107
369  *****************************************************************************/
370 /* Darwin port : namespace clash with Darwin's WriteResource */
371 int vlc_WriteResource( resource_file_t *p_file, char *psz_name, int i_type,
372                        size_t size, byte_t *p_data )
373 {
374     int i_index;                                           /* resource index */
375     int i_tmp_index;                             /* temporary resource index */
376     u64 i_offset;                                                  /* offset */
377
378 #ifdef DEBUG
379     if( p_file->b_read_only )
380     {
381         intf_DbgMsg("rsc debug 107-1: can not write to a read-only resource file");
382         return( -1 );
383     }
384 #endif
385
386     /* Look for an empty place in the resources table */
387     i_index = -1;
388     i_offset = p_file->i_size * 50 + 8;
389     for( i_tmp_index = 0; i_tmp_index < p_file->i_size; i_tmp_index++ )
390     {
391         if( p_file->p_resource[i_tmp_index].i_type != EMPTY_RESOURCE)
392         {
393             i_offset = MAX( i_offset, p_file->p_resource[i_tmp_index].i_offset
394                             + p_file->p_resource[i_tmp_index].i_size );
395         }
396         else if( i_index == -1 )
397         {
398             i_index = i_tmp_index;
399         }
400     }
401     if( i_index == -1 )
402     {
403         intf_ErrMsg("rsc error 107-1: resources table is full");
404         return( -1 );
405     }
406
407     /* Seek end of file */
408     if( lseek( p_file->i_file, i_offset, SEEK_SET ) )
409     {
410         intf_ErrMsg("rsc error 107-2: %s", strerror(errno));
411         return( -2 );
412     }
413
414     /* Write data */
415     if( write( p_file->i_file, p_data, size ) != size )
416     {
417         intf_ErrMsg("rsc error 107-3: %s", strerror(errno));
418         return( -3 );
419     }
420
421     /* Update table */
422     strncpy( p_file->p_resource[i_index].psz_name, psz_name, RESOURCE_MAX_NAME );
423     p_file->p_resource[i_index].psz_name[RESOURCE_MAX_NAME] = '\0';
424     p_file->p_resource[i_index].i_type = i_type;
425     p_file->p_resource[i_index].i_offset = i_offset;
426     p_file->p_resource[i_index].i_size = size;
427     p_file->b_up_to_date = 0;
428
429     return( 0 );
430 }