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