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 $
9 * Authors: Vincent Seguin <seguin@via.ecp.fr>
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.
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.
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 *****************************************************************************/
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 *****************************************************************************/
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() */
57 #include "rsc_files.h"
61 /*****************************************************************************
62 * CreateResourceFile: create a new resource file
63 *****************************************************************************
64 * Creates a new resource file. The file is opened read/write and erased if
66 *****************************************************************************
67 * Messages type: rsc, major code 101
68 *****************************************************************************/
69 resource_file_t *CreateResourceFile( char *psz_filename, int i_type, int i_size,
72 resource_file_t * p_file; /* new descriptor */
73 int i_index; /* resource index */
75 /* Create descriptor and tables */
76 p_file = malloc( sizeof(resource_file_t) );
79 intf_ErrMsg("rsc error 101-1: %s", strerror(errno));
82 p_file->p_resource = malloc( sizeof(resource_descriptor_t) * i_size );
83 if( p_file->p_resource == NULL )
85 intf_ErrMsg("rsc error 101-2: %s", strerror(errno));
91 p_file->i_file = open( psz_filename, O_CREAT | O_RDWR, i_mode );
92 if( p_file->i_file == -1 ) /* error */
94 intf_ErrMsg("rsc error 101-3: %s: %s", psz_filename, strerror(errno) );
95 free( p_file->p_resource );
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++ )
105 p_file->p_resource[i_index].i_type = EMPTY_RESOURCE;
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 )
121 resource_file_t * p_file; /* new descriptor */
122 int i_index; /* resource index */
123 byte_t p_buffer[50]; /* buffer */
125 /* Create descriptor and tables */
126 p_file = malloc( sizeof(resource_file_t) );
129 intf_ErrMsg("rsc error 102-1: %s", strerror(errno));
134 p_file->i_file = open( psz_filename, i_flags );
135 if( p_file->i_file == -1 ) /* error */
137 intf_ErrMsg("rsc error 102-2: %s: %s", psz_filename, strerror(errno) );
143 if( read( p_file->i_file, p_buffer, 8 ) != 8)
145 intf_ErrMsg("rsc error 102-3: %s: unexpected end of file (not a resource file ?)");
146 close( p_file->i_file );
150 if( (p_buffer[0] != 'R') || (p_buffer[0] != 'F') || (*(u16 *)(p_buffer + 4) != i_type) )
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 );
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);
161 /* Allocate tables */
162 p_file->p_resource = malloc( sizeof(resource_descriptor_t) * p_file->i_size );
163 if( p_file->p_resource == NULL )
165 intf_ErrMsg("rsc error 102-5: %s", strerror(errno));
166 close( p_file->i_file );
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++ )
176 if( read( p_file->i_file, p_buffer, 50 ) != 50 )
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 );
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 );
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 )
204 byte_t p_buffer[50]; /* buffer */
205 int i_index; /* resource index */
208 if( p_file->b_read_only )
210 intf_DbgMsg("rsc debug 103-1: can't update a read-only file");
215 /* Seek beginning of file */
216 if( lseek( p_file->i_file, 0, SEEK_SET ) )
218 intf_ErrMsg("rsc error 103-1: %s", strerror(errno));
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 )
231 intf_ErrMsg("rsc error 103-2: %s", strerror(errno));
235 /* Write resources table */
236 for( i_index = 0; i_index < p_file->i_size; i_index++ )
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 )
244 intf_ErrMsg("rsc error 103-3: %s", strerror(errno));
249 /* Mark file as up to date */
250 p_file->b_up_to_date = 1;
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 )
266 if( !p_file->b_up_to_date && ( UpdateResourceFile( p_file ) < 0 ) )
271 /* Close and destroy descriptor */
272 if( close( p_file->i_file ) )
274 intf_ErrMsg("rsc error 104-1: %s", strerror(errno));
277 free( p_file->p_resource );
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
287 * In case of success, the resource number is returned. Else, a negative number
289 *****************************************************************************
290 * Messages type: rsc, major code 105
291 *****************************************************************************/
292 int SeekResource( resource_file_t *p_file, char *psz_name, int i_type )
294 int i_index; /* resource index */
296 /* Look for resource in table */
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));
305 if( i_index == p_file->i_size )
307 intf_ErrMsg("rsc error 105-1: unknown resource %s.%d", psz_name, i_type);
312 if( lseek( p_file->i_file, p_file->p_resource[i_index].i_offset, SEEK_SET ) )
314 intf_ErrMsg("rsc error 105-2: can not reach %s.%d: %s", psz_name,
315 i_type, strerror(errno));
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 )
333 int i_index; /* resource index */
336 i_index = SeekResource( p_file, psz_name, i_type );
342 /* Check if buffer is large enough */
343 if( max_size < p_file->p_resource[i_index].i_size )
345 intf_ErrMsg("rsc error 106-1: buffer is too small");
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 )
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,
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 )
374 int i_index; /* resource index */
375 int i_tmp_index; /* temporary resource index */
376 u64 i_offset; /* offset */
379 if( p_file->b_read_only )
381 intf_DbgMsg("rsc debug 107-1: can not write to a read-only resource file");
386 /* Look for an empty place in the resources table */
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++ )
391 if( p_file->p_resource[i_tmp_index].i_type != EMPTY_RESOURCE)
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 );
396 else if( i_index == -1 )
398 i_index = i_tmp_index;
403 intf_ErrMsg("rsc error 107-1: resources table is full");
407 /* Seek end of file */
408 if( lseek( p_file->i_file, i_offset, SEEK_SET ) )
410 intf_ErrMsg("rsc error 107-2: %s", strerror(errno));
415 if( write( p_file->i_file, p_data, size ) != size )
417 intf_ErrMsg("rsc error 107-3: %s", strerror(errno));
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;