1 /*
2   Copyright (C) 2004-2005, 2008, 2010-2011, 2013, 2017
3    Rocky Bernstein <rocky@gnu.org>
4 
5   This program is free software: you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation, either version 3 of the License, or
8   (at your option) any later version.
9 
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14 
15   You should have received a copy of the GNU General Public License
16   along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18 
19 /*! Common image routines.
20 
21   Because _img_private_t may vary over image formats, the routines are
22   included into the image drivers after _img_private_t is defined.  In
23   order for the below routines to work, there is a large part of
24   _img_private_t that is common among image drivers. For example, see
25   image.h
26 */
27 
28 #include "image.h"
29 #include "image_common.h"
30 #include <cdio/util.h>
31 #include "_cdio_stdio.h"
32 
33 #ifdef HAVE_STDLIB_H
34 #include <stdlib.h>
35 #endif
36 
37 #ifdef HAVE_STRING_H
38 #include <string.h>
39 #endif
40 
41 /*!
42   Eject media -- there's nothing to do here except free resources.
43   We always return DRIVER_OP_UNSUPPORTED.
44  */
45 driver_return_code_t
_eject_media_image(void * p_user_data)46 _eject_media_image(void *p_user_data)
47 {
48   _free_image (p_user_data);
49   return DRIVER_OP_UNSUPPORTED;
50 }
51 
52 /*!
53   We don't need the image any more. Free all memory associated with
54   it.
55  */
56 void
_free_image(void * p_user_data)57 _free_image (void *p_user_data)
58 {
59   _img_private_t *p_env = p_user_data;
60   track_t i_track;
61 
62   if (NULL == p_env) return;
63 
64   for (i_track=0; i_track < p_env->gen.i_tracks; i_track++) {
65     track_info_t *p_tocent = &(p_env->tocent[i_track]);
66     CDIO_FREE_IF_NOT_NULL(p_tocent->filename);
67     CDIO_FREE_IF_NOT_NULL(p_tocent->isrc);
68     if (p_tocent->data_source) cdio_stdio_destroy(p_tocent->data_source);
69   }
70 
71   CDIO_FREE_IF_NOT_NULL(p_env->psz_mcn);
72   CDIO_FREE_IF_NOT_NULL(p_env->psz_cue_name);
73   CDIO_FREE_IF_NOT_NULL(p_env->psz_access_mode);
74   cdtext_destroy(p_env->gen.cdtext);
75   cdio_generic_stdio_free(p_env);
76   free(p_env);
77 }
78 
79 /*!
80   Return the value associated with the key "arg".
81 */
82 const char *
_get_arg_image(void * user_data,const char key[])83 _get_arg_image (void *user_data, const char key[])
84 {
85   _img_private_t *p_env = user_data;
86 
87   if (!strcmp (key, "source")) {
88     return p_env->gen.source_name;
89   } else if (!strcmp (key, "cue")) {
90     return p_env->psz_cue_name;
91   } else if (!strcmp(key, "access-mode")) {
92     return "image";
93   } else if (!strcmp (key, "mmc-supported?")) {
94     return "false";
95   }
96   return NULL;
97 }
98 
99 /*!
100   Return CD-Text object
101  */
102 cdtext_t *
_get_cdtext_image(void * user_data)103 _get_cdtext_image (void *user_data)
104 {
105   generic_img_private_t *p_env = user_data;
106 
107   if(!p_env)
108     return NULL;
109 
110   return p_env->cdtext;
111 }
112 
113 /*!
114   Get disc type associated with cd_obj.
115 */
116 discmode_t
_get_discmode_image(void * p_user_data)117 _get_discmode_image (void *p_user_data)
118 {
119   _img_private_t *p_env = p_user_data;
120   return p_env->disc_mode;
121 }
122 
123 /*!
124   Return the the kind of drive capabilities of device.
125 
126  */
127 void
_get_drive_cap_image(const void * user_data,cdio_drive_read_cap_t * p_read_cap,cdio_drive_write_cap_t * p_write_cap,cdio_drive_misc_cap_t * p_misc_cap)128 _get_drive_cap_image (const void *user_data,
129 		      cdio_drive_read_cap_t  *p_read_cap,
130 		      cdio_drive_write_cap_t *p_write_cap,
131 		      cdio_drive_misc_cap_t  *p_misc_cap)
132 {
133 
134   *p_read_cap  = CDIO_DRIVE_CAP_READ_CD_DA
135     | CDIO_DRIVE_CAP_READ_CD_G
136     | CDIO_DRIVE_CAP_READ_CD_R
137     | CDIO_DRIVE_CAP_READ_CD_RW
138     | CDIO_DRIVE_CAP_READ_MODE2_FORM1
139     | CDIO_DRIVE_CAP_READ_MODE2_FORM2
140     | CDIO_DRIVE_CAP_READ_MCN
141     ;
142 
143   *p_write_cap = 0;
144 
145   /* In the future we may want to simulate
146      LOCK, OPEN_TRAY, CLOSE_TRAY, SELECT_SPEED, etc.
147   */
148   *p_misc_cap  = CDIO_DRIVE_CAP_MISC_FILE;
149 }
150 
151 /*!
152   Return the number of of the first track.
153   CDIO_INVALID_TRACK is returned on error.
154 */
155 track_t
_get_first_track_num_image(void * p_user_data)156 _get_first_track_num_image(void *p_user_data)
157 {
158   _img_private_t *p_env = p_user_data;
159 
160   if (!p_env->gen.toc_init)
161     p_env->gen.cdio->op.read_toc (p_user_data);
162 
163   return p_env->gen.toc_init ? p_env->gen.i_first_track : CDIO_INVALID_TRACK;
164 }
165 
166 /*!
167   Find out if media has changed since the last call.
168   @param p_user_data the CD object to be acted upon.
169   @return 1 if media has changed since last call, 0 if not. Error
170   return codes are the same as driver_return_code_t
171   There is no such thing as changing a media image so we will
172   always return 0 - no change.
173  */
174 int
get_media_changed_image(const void * p_user_data)175 get_media_changed_image(const void *p_user_data)
176 {
177   return 0;
178 }
179 
180 /*!
181   Return the media catalog number (MCN) from the CD or NULL if there
182   is none or we don't have the ability to get it.
183 
184   Note: string is malloc'd so caller has to free() the returned
185   string when done with it.
186   */
187 char *
_get_mcn_image(const void * p_user_data)188 _get_mcn_image(const void *p_user_data)
189 {
190   const _img_private_t *p_env = p_user_data;
191 
192   if (!p_env || !p_env->psz_mcn) return NULL;
193   return strdup(p_env->psz_mcn);
194 }
195 
196 /*!
197   Return the number of tracks.
198 */
199 track_t
_get_num_tracks_image(void * p_user_data)200 _get_num_tracks_image(void *p_user_data)
201 {
202   _img_private_t *p_env = p_user_data;
203 
204   return p_env->gen.i_tracks;
205 }
206 
207 /*!
208   Return the starting MSF (minutes/secs/frames) for the track number
209   track_num in obj.  Tracks numbers start at 1.
210   The "leadout" track is specified either by
211   using track_num LEADOUT_TRACK or the total tracks+1.
212 
213 */
214 bool
_get_track_msf_image(void * p_user_data,track_t i_track,msf_t * msf)215 _get_track_msf_image(void *p_user_data, track_t i_track, msf_t *msf)
216 {
217   const _img_private_t *p_env = p_user_data;
218 
219   if (NULL == msf) return false;
220 
221   if (i_track == CDIO_CDROM_LEADOUT_TRACK)
222     i_track = p_env->gen.i_tracks + p_env->gen.i_first_track;
223 
224   if (i_track >= p_env->gen.i_first_track &&
225       i_track <= p_env->gen.i_tracks + p_env->gen.i_first_track) {
226     *msf = p_env->tocent[i_track-p_env->gen.i_first_track].start_msf;
227     return true;
228   } else
229     return false;
230 }
231 
232 /*! Return number of channels in track: 2 or 4; -2 if not
233   implemented or -1 for error.
234   Not meaningful if track is not an audio track.
235 */
236 int
get_track_channels_image(const void * p_user_data,track_t i_track)237 get_track_channels_image(const void *p_user_data, track_t i_track)
238 {
239   const _img_private_t *p_env = p_user_data;
240   return ( p_env->tocent[i_track-p_env->gen.i_first_track].flags
241 	  & FOUR_CHANNEL_AUDIO ) ? 4 : 2;
242 }
243 
244 /*! Return 1 if copy is permitted on the track, 0 if not, or -1 for error.
245   Is this meaningful if not an audio track?
246 */
247 track_flag_t
get_track_copy_permit_image(void * p_user_data,track_t i_track)248 get_track_copy_permit_image(void *p_user_data, track_t i_track)
249 {
250   const _img_private_t *p_env = p_user_data;
251   return ( p_env->tocent[i_track-p_env->gen.i_first_track].flags
252 	   & COPY_PERMITTED ) ? CDIO_TRACK_FLAG_TRUE : CDIO_TRACK_FLAG_FALSE;
253 }
254 
255 /*! Return 1 if track has pre-emphasis, 0 if not, or -1 for error.
256   Is this meaningful if not an audio track?
257 
258   pre-emphasis is a non linear frequency response.
259 */
260 track_flag_t
get_track_preemphasis_image(const void * p_user_data,track_t i_track)261 get_track_preemphasis_image(const void *p_user_data, track_t i_track)
262 {
263   const _img_private_t *p_env = p_user_data;
264   return ( p_env->tocent[i_track-p_env->gen.i_first_track].flags
265 	   & PRE_EMPHASIS ) ? CDIO_TRACK_FLAG_TRUE : CDIO_TRACK_FLAG_FALSE;
266 }
267 
268 /*! Return the starting LBA for the pregap for track number i_track.
269   Track numbers start at 1.
270   CDIO_INVALID_LBA is returned on error.
271 */
272 lba_t
get_track_pregap_lba_image(const void * p_user_data,track_t i_track)273 get_track_pregap_lba_image(const void *p_user_data, track_t i_track)
274 {
275   const _img_private_t *p_env = p_user_data;
276   lba_t pregap, start_lba;
277 
278   pregap    = p_env->tocent[i_track-p_env->gen.i_first_track].pregap;
279   start_lba = p_env->tocent[i_track-p_env->gen.i_first_track].start_lba;
280 
281   /* avoid initializing pregap to CDIO_INVALID_LBA by letting calloc
282      do the work.  also, nero files have the pregap set equal
283      to the start of the track when there is no pregap
284   */
285   if (!pregap || pregap == start_lba) {
286     pregap = CDIO_INVALID_LBA;
287   }
288 
289   return pregap;
290 }
291 
292 /*!
293   Return the International Standard Recording Code (ISRC) for track number
294   i_track in p_cdio.  Track numbers start at 1.
295 
296   Note: string is malloc'd so caller has to free() the returned
297   string when done with it.
298 */
299 char *
get_track_isrc_image(const void * p_user_data,track_t i_track)300 get_track_isrc_image(const void *p_user_data, track_t i_track)
301 {
302   const _img_private_t *p_env = p_user_data;
303   char *isrc = p_env->tocent[i_track-p_env->gen.i_first_track].isrc;
304 
305   if (isrc && isrc[0]) {
306     return strdup(isrc);
307   } else {
308     return NULL;
309   }
310 }
311 
312 /*!
313   Read a data sector
314 
315   @param p_cdio object to read from
316 
317   @param p_buf place to read data into.  The caller should make sure
318   this location can store at least ISO_BLOCKSIZE, M2RAW_SECTOR_SIZE,
319   or M2F2_SECTOR_SIZE depending on the kind of sector getting read. If
320   you don't know whether you have a Mode 1/2, Form 1/ Form 2/Formless
321   sector best to reserve space for the maximum, M2RAW_SECTOR_SIZE.
322 
323   @param i_lsn sector to read
324 
325   @param i_blocksize size of block. Should be either ISO_BLOCKSIZE
326   M2RAW_SECTOR_SIZE, or M2F2_SECTOR_SIZE. See comment above under
327   p_buf.
328   */
329 driver_return_code_t
read_data_sectors_image(void * p_user_data,void * p_buf,lsn_t i_lsn,uint16_t i_blocksize,uint32_t i_blocks)330 read_data_sectors_image ( void *p_user_data, void *p_buf,
331 			  lsn_t i_lsn,  uint16_t i_blocksize,
332 			  uint32_t i_blocks )
333 {
334   const _img_private_t *p_env = p_user_data;
335 
336   if (!p_env || !p_env->gen.cdio) return DRIVER_OP_UNINIT;
337 
338   {
339     CdIo_t *p_cdio                = p_env->gen.cdio;
340     track_t i_track               = cdio_get_track(p_cdio, i_lsn);
341     track_format_t e_track_format = cdio_get_track_format(p_cdio, i_track);
342 
343     switch(e_track_format) {
344     case TRACK_FORMAT_PSX:
345     case TRACK_FORMAT_AUDIO:
346     case TRACK_FORMAT_ERROR:
347       return DRIVER_OP_ERROR;
348     case TRACK_FORMAT_DATA:
349       return cdio_read_mode1_sectors (p_cdio, p_buf, i_lsn, false, i_blocks);
350     case TRACK_FORMAT_CDI:
351     case TRACK_FORMAT_XA:
352       return cdio_read_mode2_sectors (p_cdio, p_buf, i_lsn, false, i_blocks);
353     }
354   }
355   return DRIVER_OP_ERROR;
356 }
357 
358 
359 /*!
360   Set the arg "key" with "value" in the source device.
361   Currently "source" to set the source device in I/O operations
362   is the only valid key.
363 
364 */
365 driver_return_code_t
_set_arg_image(void * p_user_data,const char key[],const char value[])366 _set_arg_image (void *p_user_data, const char key[], const char value[])
367 {
368   _img_private_t *p_env = p_user_data;
369 
370   if (!strcmp (key, "source"))
371     {
372       CDIO_FREE_IF_NOT_NULL(p_env->gen.source_name);
373       if (!value) return DRIVER_OP_ERROR;
374       p_env->gen.source_name = strdup (value);
375     }
376   else if (!strcmp (key, "cue"))
377     {
378       CDIO_FREE_IF_NOT_NULL(p_env->psz_cue_name);
379       if (!value) return DRIVER_OP_ERROR;
380       p_env->psz_cue_name = strdup (value);
381     }
382   else if (!strcmp (key, "access-mode"))
383     {
384       CDIO_FREE_IF_NOT_NULL(p_env->psz_access_mode);
385       if (!value) return DRIVER_OP_ERROR;
386       p_env->psz_access_mode = strdup (value);
387     }
388   else
389     return DRIVER_OP_ERROR;
390 
391   return DRIVER_OP_SUCCESS;
392 }
393