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
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.
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.
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 *****************************************************************************/
26 /*****************************************************************************
27 * Format of a resource file:
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.
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
40 *****************************************************************************/
42 /*****************************************************************************
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() */
55 #include "rsc_files.h"
59 /*****************************************************************************
60 * CreateResourceFile: create a new resource file
61 *****************************************************************************
62 * Creates a new resource file. The file is opened read/write and erased if
64 *****************************************************************************
65 * Messages type: rsc, major code 101
66 *****************************************************************************/
67 resource_file_t *CreateResourceFile( char *psz_filename, int i_type, int i_size,
70 resource_file_t * p_file; /* new descriptor */
71 int i_index; /* resource index */
73 /* Create descriptor and tables */
74 p_file = malloc( sizeof(resource_file_t) );
77 intf_ErrMsg("rsc error 101-1: %s\n", strerror(errno));
80 p_file->p_resource = malloc( sizeof(resource_descriptor_t) * i_size );
81 if( p_file->p_resource == NULL )
83 intf_ErrMsg("rsc error 101-2: %s\n", strerror(errno));
89 p_file->i_file = open( psz_filename, O_CREAT | O_RDWR, i_mode );
90 if( p_file->i_file == -1 ) /* error */
92 intf_ErrMsg("rsc error 101-3: %s: %s\n", psz_filename, strerror(errno) );
93 free( p_file->p_resource );
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++ )
103 p_file->p_resource[i_index].i_type = EMPTY_RESOURCE;
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 )
119 resource_file_t * p_file; /* new descriptor */
120 int i_index; /* resource index */
121 byte_t p_buffer[50]; /* buffer */
123 /* Create descriptor and tables */
124 p_file = malloc( sizeof(resource_file_t) );
127 intf_ErrMsg("rsc error 102-1: %s\n", strerror(errno));
132 p_file->i_file = open( psz_filename, i_flags );
133 if( p_file->i_file == -1 ) /* error */
135 intf_ErrMsg("rsc error 102-2: %s: %s\n", psz_filename, strerror(errno) );
141 if( read( p_file->i_file, p_buffer, 8 ) != 8)
143 intf_ErrMsg("rsc error 102-3: %s: unexpected end of file (not a resource file ?)\n");
144 close( p_file->i_file );
148 if( (p_buffer[0] != 'R') || (p_buffer[0] != 'F') || (*(u16 *)(p_buffer + 4) != i_type) )
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 );
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);
159 /* Allocate tables */
160 p_file->p_resource = malloc( sizeof(resource_descriptor_t) * p_file->i_size );
161 if( p_file->p_resource == NULL )
163 intf_ErrMsg("rsc error 102-5: %s\n", strerror(errno));
164 close( p_file->i_file );
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++ )
174 if( read( p_file->i_file, p_buffer, 50 ) != 50 )
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 );
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 );
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 )
202 byte_t p_buffer[50]; /* buffer */
203 int i_index; /* resource index */
206 if( p_file->b_read_only )
208 intf_DbgMsg("rsc debug 103-1: can't update a read-only file\n");
213 /* Seek beginning of file */
214 if( lseek( p_file->i_file, 0, SEEK_SET ) )
216 intf_ErrMsg("rsc error 103-1: %s\n", strerror(errno));
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 )
229 intf_ErrMsg("rsc error 103-2: %s\n", strerror(errno));
233 /* Write resources table */
234 for( i_index = 0; i_index < p_file->i_size; i_index++ )
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 )
242 intf_ErrMsg("rsc error 103-3: %s\n", strerror(errno));
247 /* Mark file as up to date */
248 p_file->b_up_to_date = 1;
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 )
264 if( !p_file->b_up_to_date && ( UpdateResourceFile( p_file ) < 0 ) )
269 /* Close and destroy descriptor */
270 if( close( p_file->i_file ) )
272 intf_ErrMsg("rsc error 104-1: %s\n", strerror(errno));
275 free( p_file->p_resource );
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
285 * In case of success, the resource number is returned. Else, a negative number
287 *****************************************************************************
288 * Messages type: rsc, major code 105
289 *****************************************************************************/
290 int SeekResource( resource_file_t *p_file, char *psz_name, int i_type )
292 int i_index; /* resource index */
294 /* Look for resource in table */
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));
303 if( i_index == p_file->i_size )
305 intf_ErrMsg("rsc error 105-1: unknown resource %s.%d\n", psz_name, i_type);
310 if( lseek( p_file->i_file, p_file->p_resource[i_index].i_offset, SEEK_SET ) )
312 intf_ErrMsg("rsc error 105-2: can not reach %s.%d: %s\n", psz_name,
313 i_type, strerror(errno));
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 )
331 int i_index; /* resource index */
334 i_index = SeekResource( p_file, psz_name, i_type );
340 /* Check if buffer is large enough */
341 if( max_size < p_file->p_resource[i_index].i_size )
343 intf_ErrMsg("rsc error 106-1: buffer is too small\n");
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 )
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,
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 )
371 int i_index; /* resource index */
372 int i_tmp_index; /* temporary resource index */
373 u64 i_offset; /* offset */
376 if( p_file->b_read_only )
378 intf_DbgMsg("rsc debug 107-1: can not write to a read-only resource file\n");
383 /* Look for an empty place in the resources table */
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++ )
388 if( p_file->p_resource[i_tmp_index].i_type != EMPTY_RESOURCE)
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 );
393 else if( i_index == -1 )
395 i_index = i_tmp_index;
400 intf_ErrMsg("rsc error 107-1: resources table is full\n");
404 /* Seek end of file */
405 if( lseek( p_file->i_file, i_offset, SEEK_SET ) )
407 intf_ErrMsg("rsc error 107-2: %s\n", strerror(errno));
412 if( write( p_file->i_file, p_data, size ) != size )
414 intf_ErrMsg("rsc error 107-3: %s\n", strerror(errno));
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;