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
8 * Authors: Vincent Seguin <seguin@via.ecp.fr>
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
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
23 *****************************************************************************/
25 /*****************************************************************************
26 * Format of a resource file:
28 * 0 char[2] "RF" (magic number)
29 * 2 char[2] "VL" (minor magic number, ignored)
30 * 4 u16 i_type: resource file type. This is to allow
31 * different versions of the resources types constants.
32 * 6 u16 i_size: number of entries in the resources table.
34 * +0 char[32] resource name (ASCIIZ or ASCII[32])
35 * +32 u16 resource type
36 * +34 u64 data offset in bytes, from beginning of file
37 * +42 u64 data size in bytes
39 *****************************************************************************/
41 /*****************************************************************************
43 *****************************************************************************/
46 #include <errno.h> /* errno */
47 #include <fcntl.h> /* open() */
48 #include <stdlib.h> /* free() */
49 #include <string.h> /* strerror(), strncopy() */
50 #include <unistd.h> /* read(), close(), lseek(), write() */
56 #include "rsc_files.h"
60 /*****************************************************************************
61 * CreateResourceFile: create a new resource file
62 *****************************************************************************
63 * Creates a new resource file. The file is opened read/write and erased if
65 *****************************************************************************
66 * Messages type: rsc, major code 101
67 *****************************************************************************/
68 resource_file_t *CreateResourceFile( char *psz_filename, int i_type, int i_size,
71 resource_file_t * p_file; /* new descriptor */
72 int i_index; /* resource index */
74 /* Create descriptor and tables */
75 p_file = malloc( sizeof(resource_file_t) );
78 intf_ErrMsg("rsc error 101-1: %s", strerror(errno));
81 p_file->p_resource = malloc( sizeof(resource_descriptor_t) * i_size );
82 if( p_file->p_resource == NULL )
84 intf_ErrMsg("rsc error 101-2: %s", strerror(errno));
90 p_file->i_file = open( psz_filename, O_CREAT | O_RDWR, i_mode );
91 if( p_file->i_file == -1 ) /* error */
93 intf_ErrMsg("rsc error 101-3: %s: %s", psz_filename, strerror(errno) );
94 free( p_file->p_resource );
98 /* Initialize tables */
99 p_file->i_type = i_type;
100 p_file->i_size = i_size;
101 p_file->b_read_only = 0;
102 for( i_index = 0; i_index < i_size; i_index++ )
104 p_file->p_resource[i_index].i_type = EMPTY_RESOURCE;
110 /*****************************************************************************
111 * OpenResourceFile: open an existing resource file read-only
112 *****************************************************************************
113 * Open an existing resource file. i_flags should be O_RDONLY or O_RDWR. An
114 * error will occurs if the file does not exists.
115 *****************************************************************************
116 * Messages type: rsc, major code 102
117 *****************************************************************************/
118 resource_file_t *OpenResourceFile( char *psz_filename, int i_type, int i_flags )
120 resource_file_t * p_file; /* new descriptor */
121 int i_index; /* resource index */
122 byte_t p_buffer[50]; /* buffer */
124 /* Create descriptor and tables */
125 p_file = malloc( sizeof(resource_file_t) );
128 intf_ErrMsg("rsc error 102-1: %s", strerror(errno));
133 p_file->i_file = open( psz_filename, i_flags );
134 if( p_file->i_file == -1 ) /* error */
136 intf_ErrMsg("rsc error 102-2: %s: %s", psz_filename, strerror(errno) );
142 if( read( p_file->i_file, p_buffer, 8 ) != 8)
144 intf_ErrMsg("rsc error 102-3: %s: unexpected end of file (not a resource file ?)");
145 close( p_file->i_file );
149 if( (p_buffer[0] != 'R') || (p_buffer[0] != 'F') || (*(u16 *)(p_buffer + 4) != i_type) )
151 intf_ErrMsg("rsc error 102-4: %s is not a valid resource file or has incorrect type", psz_filename);
152 close( p_file->i_file );
156 p_file->i_type = i_type;
157 p_file->i_size = *(u16 *)(p_buffer + 6);
158 intf_DbgMsg("rsc debug 102-1: %s opened, %d resources", psz_filename, p_file->i_size);
160 /* Allocate tables */
161 p_file->p_resource = malloc( sizeof(resource_descriptor_t) * p_file->i_size );
162 if( p_file->p_resource == NULL )
164 intf_ErrMsg("rsc error 102-5: %s", strerror(errno));
165 close( p_file->i_file );
170 /* Initialize table */
171 p_file->b_up_to_date = 1;
172 p_file->b_read_only = ( i_flags & O_RDWR ) ? 0 : 1;
173 for( i_index = 0; i_index < p_file->i_size; i_index++ )
175 if( read( p_file->i_file, p_buffer, 50 ) != 50 )
177 intf_ErrMsg("rsc error 102-6: %s: unexpected end of file", psz_filename);
178 close( p_file->i_file );
179 free( p_file->p_resource );
183 memcpy( p_file->p_resource[i_index].psz_name, p_buffer, 32 );
184 p_file->p_resource[i_index].psz_name[RESOURCE_MAX_NAME] = '\0';
185 p_file->p_resource[i_index].i_type = *(u16 *)(p_buffer + 32 );
186 p_file->p_resource[i_index].i_offset = *(u64 *)(p_buffer + 34 );
187 p_file->p_resource[i_index].i_size = *(u64 *)(p_buffer + 42 );
193 /*****************************************************************************
194 * UpdateResourceFile: write the resources table in a resource file
195 *****************************************************************************
196 * This function writes resources table in the resource file. This is
197 * automatically done when the file is closed, but can also be done manually.
198 *****************************************************************************
199 * Messages type: rsc, major code 103
200 *****************************************************************************/
201 int UpdateResourceFile( resource_file_t *p_file )
203 byte_t p_buffer[50]; /* buffer */
204 int i_index; /* resource index */
207 if( p_file->b_read_only )
209 intf_DbgMsg("rsc debug 103-1: can't update a read-only file");
214 /* Seek beginning of file */
215 if( lseek( p_file->i_file, 0, SEEK_SET ) )
217 intf_ErrMsg("rsc error 103-1: %s", strerror(errno));
226 *(u16 *)(p_buffer + 4) = p_file->i_type;
227 *(u16 *)(p_buffer + 6) = p_file->i_size;
228 if( write( p_file->i_file, p_buffer, 8 ) != 8 )
230 intf_ErrMsg("rsc error 103-2: %s", strerror(errno));
234 /* Write resources table */
235 for( i_index = 0; i_index < p_file->i_size; i_index++ )
237 memcpy( p_buffer, p_file->p_resource[i_index].psz_name, 32 );
238 *(u16 *)(p_buffer + 32) = p_file->p_resource[i_index].i_type;
239 *(u64 *)(p_buffer + 34) = p_file->p_resource[i_index].i_offset;
240 *(u64 *)(p_buffer + 42) = p_file->p_resource[i_index].i_size;
241 if( write( p_file->i_file, p_buffer, 8 ) != 8 )
243 intf_ErrMsg("rsc error 103-3: %s", strerror(errno));
248 /* Mark file as up to date */
249 p_file->b_up_to_date = 1;
254 /*****************************************************************************
255 * CloseResourceFile: close a resource file
256 *****************************************************************************
257 * Updates the resources table if required, and close the file. It returns non
258 * 0 in case of error.
259 *****************************************************************************
260 * Messages type: rsc, major code 104
261 *****************************************************************************/
262 int CloseResourceFile( resource_file_t *p_file )
265 if( !p_file->b_up_to_date && ( UpdateResourceFile( p_file ) < 0 ) )
270 /* Close and destroy descriptor */
271 if( close( p_file->i_file ) )
273 intf_ErrMsg("rsc error 104-1: %s", strerror(errno));
276 free( p_file->p_resource );
281 /*****************************************************************************
282 * SeekResource: seek a resource in a resource file
283 *****************************************************************************
284 * Look for a resource in file and place the "reading head" at the beginning of
286 * In case of success, the resource number is returned. Else, a negative number
288 *****************************************************************************
289 * Messages type: rsc, major code 105
290 *****************************************************************************/
291 int SeekResource( resource_file_t *p_file, char *psz_name, int i_type )
293 int i_index; /* resource index */
295 /* Look for resource in table */
297 (i_index < p_file->i_size)
298 && ((i_type != p_file->p_resource[i_index].i_type )
299 || strcmp(psz_name, p_file->p_resource[i_index].psz_name));
304 if( i_index == p_file->i_size )
306 intf_ErrMsg("rsc error 105-1: unknown resource %s.%d", psz_name, i_type);
311 if( lseek( p_file->i_file, p_file->p_resource[i_index].i_offset, SEEK_SET ) )
313 intf_ErrMsg("rsc error 105-2: can not reach %s.%d: %s", psz_name,
314 i_type, strerror(errno));
321 /*****************************************************************************
322 * ReadResource: read a resource
323 *****************************************************************************
324 * Read a resource from a file. The function returns a negative value in case
325 * of error, and 0 in case of success.
326 *****************************************************************************
327 * Messages type: rsc, major code 106
328 *****************************************************************************/
329 int ReadResource( resource_file_t *p_file, char *psz_name, int i_type,
330 size_t max_size, byte_t *p_data )
332 int i_index; /* resource index */
335 i_index = SeekResource( p_file, psz_name, i_type );
341 /* Check if buffer is large enough */
342 if( max_size < p_file->p_resource[i_index].i_size )
344 intf_ErrMsg("rsc error 106-1: buffer is too small");
349 if( read( p_file->i_file, p_data, p_file->p_resource[i_index].i_size )
350 != p_file->p_resource[i_index].i_size )
352 intf_ErrMsg("rsc error 106-2: can not read %s.%d: %s",
353 p_file->p_resource[i_index].psz_name,
354 p_file->p_resource[i_index].i_type,
362 /*****************************************************************************
363 * WriteResource: write a resource
364 *****************************************************************************
365 * Append a resource at the end of the file. It returns non 0 on error.
366 *****************************************************************************
367 * Messages type: rsc, major code 107
368 *****************************************************************************/
369 /* Darwin port : namespace clash with Darwin's WriteResource */
370 int vlc_WriteResource( resource_file_t *p_file, char *psz_name, int i_type,
371 size_t size, byte_t *p_data )
373 int i_index; /* resource index */
374 int i_tmp_index; /* temporary resource index */
375 u64 i_offset; /* offset */
378 if( p_file->b_read_only )
380 intf_DbgMsg("rsc debug 107-1: can not write to a read-only resource file");
385 /* Look for an empty place in the resources table */
387 i_offset = p_file->i_size * 50 + 8;
388 for( i_tmp_index = 0; i_tmp_index < p_file->i_size; i_tmp_index++ )
390 if( p_file->p_resource[i_tmp_index].i_type != EMPTY_RESOURCE)
392 i_offset = MAX( i_offset, p_file->p_resource[i_tmp_index].i_offset
393 + p_file->p_resource[i_tmp_index].i_size );
395 else if( i_index == -1 )
397 i_index = i_tmp_index;
402 intf_ErrMsg("rsc error 107-1: resources table is full");
406 /* Seek end of file */
407 if( lseek( p_file->i_file, i_offset, SEEK_SET ) )
409 intf_ErrMsg("rsc error 107-2: %s", strerror(errno));
414 if( write( p_file->i_file, p_data, size ) != size )
416 intf_ErrMsg("rsc error 107-3: %s", strerror(errno));
421 strncpy( p_file->p_resource[i_index].psz_name, psz_name, RESOURCE_MAX_NAME );
422 p_file->p_resource[i_index].psz_name[RESOURCE_MAX_NAME] = '\0';
423 p_file->p_resource[i_index].i_type = i_type;
424 p_file->p_resource[i_index].i_offset = i_offset;
425 p_file->p_resource[i_index].i_size = size;
426 p_file->b_up_to_date = 0;