src/cdrom/macosx/SDL_syscdrom.c
branchSDL-1.3
changeset 1668 4da1ee79c9af
parent 1662 782fd950bd46
equal deleted inserted replaced
1667:1fddae038bc8 1668:4da1ee79c9af
    38 static int cacheTOCNumTracks;
    38 static int cacheTOCNumTracks;
    39 static int currentDrive;        /* Only allow 1 drive in use at a time */
    39 static int currentDrive;        /* Only allow 1 drive in use at a time */
    40 
    40 
    41 #pragma mark -- Prototypes --
    41 #pragma mark -- Prototypes --
    42 
    42 
    43 static const char *SDL_SYS_CDName (int drive);
    43 static const char *SDL_SYS_CDName(int drive);
    44 static int SDL_SYS_CDOpen (int drive);
    44 static int SDL_SYS_CDOpen(int drive);
    45 static int SDL_SYS_CDGetTOC (SDL_CD * cdrom);
    45 static int SDL_SYS_CDGetTOC(SDL_CD * cdrom);
    46 static CDstatus SDL_SYS_CDStatus (SDL_CD * cdrom, int *position);
    46 static CDstatus SDL_SYS_CDStatus(SDL_CD * cdrom, int *position);
    47 static int SDL_SYS_CDPlay (SDL_CD * cdrom, int start, int length);
    47 static int SDL_SYS_CDPlay(SDL_CD * cdrom, int start, int length);
    48 static int SDL_SYS_CDPause (SDL_CD * cdrom);
    48 static int SDL_SYS_CDPause(SDL_CD * cdrom);
    49 static int SDL_SYS_CDResume (SDL_CD * cdrom);
    49 static int SDL_SYS_CDResume(SDL_CD * cdrom);
    50 static int SDL_SYS_CDStop (SDL_CD * cdrom);
    50 static int SDL_SYS_CDStop(SDL_CD * cdrom);
    51 static int SDL_SYS_CDEject (SDL_CD * cdrom);
    51 static int SDL_SYS_CDEject(SDL_CD * cdrom);
    52 static void SDL_SYS_CDClose (SDL_CD * cdrom);
    52 static void SDL_SYS_CDClose(SDL_CD * cdrom);
    53 
    53 
    54 #pragma mark -- Helper Functions --
    54 #pragma mark -- Helper Functions --
    55 
    55 
    56 /* Read a list of tracks from the volume */
    56 /* Read a list of tracks from the volume */
    57 static int
    57 static int
    58 LoadTracks (SDL_CD * cdrom)
    58 LoadTracks(SDL_CD * cdrom)
    59 {
    59 {
    60     /* Check if tracks are already loaded */
    60     /* Check if tracks are already loaded */
    61     if (tracks[cdrom->id] != NULL)
    61     if (tracks[cdrom->id] != NULL)
    62         return 0;
    62         return 0;
    63 
    63 
    64     /* Allocate memory for tracks */
    64     /* Allocate memory for tracks */
    65     tracks[cdrom->id] =
    65     tracks[cdrom->id] =
    66         (FSRef *) SDL_calloc (1, sizeof (**tracks) * cdrom->numtracks);
    66         (FSRef *) SDL_calloc(1, sizeof(**tracks) * cdrom->numtracks);
    67     if (tracks[cdrom->id] == NULL) {
    67     if (tracks[cdrom->id] == NULL) {
    68         SDL_OutOfMemory ();
    68         SDL_OutOfMemory();
    69         return -1;
    69         return -1;
    70     }
    70     }
    71 
    71 
    72     /* Load tracks */
    72     /* Load tracks */
    73     if (ListTrackFiles
    73     if (ListTrackFiles
    77     return 0;
    77     return 0;
    78 }
    78 }
    79 
    79 
    80 /* Find a file for a given start frame and length */
    80 /* Find a file for a given start frame and length */
    81 static FSRef *
    81 static FSRef *
    82 GetFileForOffset (SDL_CD * cdrom, int start, int length, int *outStartFrame,
    82 GetFileForOffset(SDL_CD * cdrom, int start, int length, int *outStartFrame,
    83                   int *outStopFrame)
    83                  int *outStopFrame)
    84 {
    84 {
    85     int i;
    85     int i;
    86 
    86 
    87     for (i = 0; i < cdrom->numtracks; i++) {
    87     for (i = 0; i < cdrom->numtracks; i++) {
    88 
    88 
   113     return &tracks[cdrom->id][i];
   113     return &tracks[cdrom->id][i];
   114 }
   114 }
   115 
   115 
   116 /* Setup another file for playback, or stop playback (called from another thread) */
   116 /* Setup another file for playback, or stop playback (called from another thread) */
   117 static void
   117 static void
   118 CompletionProc (SDL_CD * cdrom)
   118 CompletionProc(SDL_CD * cdrom)
   119 {
   119 {
   120 
   120 
   121     Lock ();
   121     Lock();
   122 
   122 
   123     if (nextTrackFrame > 0 && nextTrackFramesRemaining > 0) {
   123     if (nextTrackFrame > 0 && nextTrackFramesRemaining > 0) {
   124 
   124 
   125         /* Load the next file to play */
   125         /* Load the next file to play */
   126         int startFrame, stopFrame;
   126         int startFrame, stopFrame;
   127         FSRef *file;
   127         FSRef *file;
   128 
   128 
   129         PauseFile ();
   129         PauseFile();
   130         ReleaseFile ();
   130         ReleaseFile();
   131 
   131 
   132         file = GetFileForOffset (cdrom, nextTrackFrame,
   132         file = GetFileForOffset(cdrom, nextTrackFrame,
   133                                  nextTrackFramesRemaining, &startFrame,
   133                                 nextTrackFramesRemaining, &startFrame,
   134                                  &stopFrame);
   134                                 &stopFrame);
   135 
   135 
   136         if (file == NULL) {
   136         if (file == NULL) {
   137             status = CD_STOPPED;
   137             status = CD_STOPPED;
   138             Unlock ();
   138             Unlock();
   139             return;
   139             return;
   140         }
   140         }
   141 
   141 
   142         LoadFile (file, startFrame, stopFrame);
   142         LoadFile(file, startFrame, stopFrame);
   143 
   143 
   144         SetCompletionProc (CompletionProc, cdrom);
   144         SetCompletionProc(CompletionProc, cdrom);
   145 
   145 
   146         PlayFile ();
   146         PlayFile();
   147     } else {
   147     } else {
   148 
   148 
   149         /* Release the current file */
   149         /* Release the current file */
   150         PauseFile ();
   150         PauseFile();
   151         ReleaseFile ();
   151         ReleaseFile();
   152         status = CD_STOPPED;
   152         status = CD_STOPPED;
   153     }
   153     }
   154 
   154 
   155     Unlock ();
   155     Unlock();
   156 }
   156 }
   157 
   157 
   158 
   158 
   159 #pragma mark -- Driver Functions --
   159 #pragma mark -- Driver Functions --
   160 
   160 
   161 /* Initialize */
   161 /* Initialize */
   162 int
   162 int
   163 SDL_SYS_CDInit (void)
   163 SDL_SYS_CDInit(void)
   164 {
   164 {
   165     /* Initialize globals */
   165     /* Initialize globals */
   166     volumes = NULL;
   166     volumes = NULL;
   167     tracks = NULL;
   167     tracks = NULL;
   168     status = CD_STOPPED;
   168     status = CD_STOPPED;
   194        actual CD-ROM devices - which means it may not
   194        actual CD-ROM devices - which means it may not
   195        act as expected sometimes.
   195        act as expected sometimes.
   196      */
   196      */
   197 
   197 
   198     /* Find out how many cd volumes are mounted */
   198     /* Find out how many cd volumes are mounted */
   199     SDL_numcds = DetectAudioCDVolumes (NULL, 0);
   199     SDL_numcds = DetectAudioCDVolumes(NULL, 0);
   200 
   200 
   201     /*
   201     /*
   202        If there are no volumes, fake a cd device
   202        If there are no volumes, fake a cd device
   203        so tray empty can be reported.
   203        so tray empty can be reported.
   204      */
   204      */
   210 
   210 
   211         return 0;
   211         return 0;
   212     }
   212     }
   213 
   213 
   214     /* Allocate space for volumes */
   214     /* Allocate space for volumes */
   215     volumes =
   215     volumes = (FSVolumeRefNum *) SDL_calloc(1, sizeof(*volumes) * SDL_numcds);
   216         (FSVolumeRefNum *) SDL_calloc (1, sizeof (*volumes) * SDL_numcds);
       
   217     if (volumes == NULL) {
   216     if (volumes == NULL) {
   218         SDL_OutOfMemory ();
   217         SDL_OutOfMemory();
   219         return -1;
   218         return -1;
   220     }
   219     }
   221 
   220 
   222     /* Allocate space for tracks */
   221     /* Allocate space for tracks */
   223     tracks = (FSRef **) SDL_calloc (1, sizeof (*tracks) * (SDL_numcds + 1));
   222     tracks = (FSRef **) SDL_calloc(1, sizeof(*tracks) * (SDL_numcds + 1));
   224     if (tracks == NULL) {
   223     if (tracks == NULL) {
   225         SDL_OutOfMemory ();
   224         SDL_OutOfMemory();
   226         return -1;
   225         return -1;
   227     }
   226     }
   228 
   227 
   229     /* Mark the end of the tracks array */
   228     /* Mark the end of the tracks array */
   230     tracks[SDL_numcds] = (FSRef *) - 1;
   229     tracks[SDL_numcds] = (FSRef *) - 1;
   234        Update SDL_numcds just in case it changed
   233        Update SDL_numcds just in case it changed
   235      */
   234      */
   236     {
   235     {
   237         int numVolumes = SDL_numcds;
   236         int numVolumes = SDL_numcds;
   238 
   237 
   239         SDL_numcds = DetectAudioCDVolumes (volumes, numVolumes);
   238         SDL_numcds = DetectAudioCDVolumes(volumes, numVolumes);
   240 
   239 
   241         /* If more cds suddenly show up, ignore them */
   240         /* If more cds suddenly show up, ignore them */
   242         if (SDL_numcds > numVolumes) {
   241         if (SDL_numcds > numVolumes) {
   243             SDL_SetError ("Some CD's were added but they will be ignored");
   242             SDL_SetError("Some CD's were added but they will be ignored");
   244             SDL_numcds = numVolumes;
   243             SDL_numcds = numVolumes;
   245         }
   244         }
   246     }
   245     }
   247 
   246 
   248     return 0;
   247     return 0;
   249 }
   248 }
   250 
   249 
   251 /* Shutdown and cleanup */
   250 /* Shutdown and cleanup */
   252 void
   251 void
   253 SDL_SYS_CDQuit (void)
   252 SDL_SYS_CDQuit(void)
   254 {
   253 {
   255     ReleaseFile ();
   254     ReleaseFile();
   256 
   255 
   257     if (volumes != NULL)
   256     if (volumes != NULL)
   258         free (volumes);
   257         free(volumes);
   259 
   258 
   260     if (tracks != NULL) {
   259     if (tracks != NULL) {
   261 
   260 
   262         FSRef **ptr;
   261         FSRef **ptr;
   263         for (ptr = tracks; *ptr != (FSRef *) - 1; ptr++)
   262         for (ptr = tracks; *ptr != (FSRef *) - 1; ptr++)
   264             if (*ptr != NULL)
   263             if (*ptr != NULL)
   265                 free (*ptr);
   264                 free(*ptr);
   266 
   265 
   267         free (tracks);
   266         free(tracks);
   268     }
   267     }
   269 }
   268 }
   270 
   269 
   271 /* Get the Unix disk name of the volume */
   270 /* Get the Unix disk name of the volume */
   272 static const char *
   271 static const char *
   273 SDL_SYS_CDName (int drive)
   272 SDL_SYS_CDName(int drive)
   274 {
   273 {
   275     OSStatus err = noErr;
   274     OSStatus err = noErr;
   276     HParamBlockRec pb;
   275     HParamBlockRec pb;
   277     GetVolParmsInfoBuffer volParmsInfo;
   276     GetVolParmsInfoBuffer volParmsInfo;
   278 
   277 
   280         return "Fake CD-ROM Device";
   279         return "Fake CD-ROM Device";
   281 
   280 
   282     pb.ioParam.ioNamePtr = NULL;
   281     pb.ioParam.ioNamePtr = NULL;
   283     pb.ioParam.ioVRefNum = volumes[drive];
   282     pb.ioParam.ioVRefNum = volumes[drive];
   284     pb.ioParam.ioBuffer = (Ptr) & volParmsInfo;
   283     pb.ioParam.ioBuffer = (Ptr) & volParmsInfo;
   285     pb.ioParam.ioReqCount = (SInt32) sizeof (volParmsInfo);
   284     pb.ioParam.ioReqCount = (SInt32) sizeof(volParmsInfo);
   286     err = PBHGetVolParmsSync (&pb);
   285     err = PBHGetVolParmsSync(&pb);
   287 
   286 
   288     if (err != noErr) {
   287     if (err != noErr) {
   289         SDL_SetError ("PBHGetVolParmsSync returned %d", err);
   288         SDL_SetError("PBHGetVolParmsSync returned %d", err);
   290         return NULL;
   289         return NULL;
   291     }
   290     }
   292 
   291 
   293     return volParmsInfo.vMDeviceID;
   292     return volParmsInfo.vMDeviceID;
   294 }
   293 }
   295 
   294 
   296 /* Open the "device" */
   295 /* Open the "device" */
   297 static int
   296 static int
   298 SDL_SYS_CDOpen (int drive)
   297 SDL_SYS_CDOpen(int drive)
   299 {
   298 {
   300     /* Only allow 1 device to be open */
   299     /* Only allow 1 device to be open */
   301     if (currentDrive >= 0) {
   300     if (currentDrive >= 0) {
   302         SDL_SetError ("Only one cdrom is supported");
   301         SDL_SetError("Only one cdrom is supported");
   303         return -1;
   302         return -1;
   304     } else
   303     } else
   305         currentDrive = drive;
   304         currentDrive = drive;
   306 
   305 
   307     return drive;
   306     return drive;
   308 }
   307 }
   309 
   308 
   310 /* Get the table of contents */
   309 /* Get the table of contents */
   311 static int
   310 static int
   312 SDL_SYS_CDGetTOC (SDL_CD * cdrom)
   311 SDL_SYS_CDGetTOC(SDL_CD * cdrom)
   313 {
   312 {
   314     if (fakeCD) {
   313     if (fakeCD) {
   315         SDL_SetError (kErrorFakeDevice);
   314         SDL_SetError(kErrorFakeDevice);
   316         return -1;
   315         return -1;
   317     }
   316     }
   318 
   317 
   319     if (didReadTOC) {
   318     if (didReadTOC) {
   320         cdrom->numtracks = cacheTOCNumTracks;
   319         cdrom->numtracks = cacheTOCNumTracks;
   321         return 0;
   320         return 0;
   322     }
   321     }
   323 
   322 
   324 
   323 
   325     ReadTOCData (volumes[cdrom->id], cdrom);
   324     ReadTOCData(volumes[cdrom->id], cdrom);
   326     didReadTOC = SDL_TRUE;
   325     didReadTOC = SDL_TRUE;
   327     cacheTOCNumTracks = cdrom->numtracks;
   326     cacheTOCNumTracks = cdrom->numtracks;
   328 
   327 
   329     return 0;
   328     return 0;
   330 }
   329 }
   331 
   330 
   332 /* Get CD-ROM status */
   331 /* Get CD-ROM status */
   333 static CDstatus
   332 static CDstatus
   334 SDL_SYS_CDStatus (SDL_CD * cdrom, int *position)
   333 SDL_SYS_CDStatus(SDL_CD * cdrom, int *position)
   335 {
   334 {
   336     if (position) {
   335     if (position) {
   337         int trackFrame;
   336         int trackFrame;
   338 
   337 
   339         Lock ();
   338         Lock();
   340         trackFrame = GetCurrentFrame ();
   339         trackFrame = GetCurrentFrame();
   341         Unlock ();
   340         Unlock();
   342 
   341 
   343         *position = cdrom->track[currentTrack].offset + trackFrame;
   342         *position = cdrom->track[currentTrack].offset + trackFrame;
   344     }
   343     }
   345 
   344 
   346     return status;
   345     return status;
   347 }
   346 }
   348 
   347 
   349 /* Start playback */
   348 /* Start playback */
   350 static int
   349 static int
   351 SDL_SYS_CDPlay (SDL_CD * cdrom, int start, int length)
   350 SDL_SYS_CDPlay(SDL_CD * cdrom, int start, int length)
   352 {
   351 {
   353     int startFrame, stopFrame;
   352     int startFrame, stopFrame;
   354     FSRef *ref;
   353     FSRef *ref;
   355 
   354 
   356     if (fakeCD) {
   355     if (fakeCD) {
   357         SDL_SetError (kErrorFakeDevice);
   356         SDL_SetError(kErrorFakeDevice);
   358         return -1;
   357         return -1;
   359     }
   358     }
   360 
   359 
   361     Lock ();
   360     Lock();
   362 
   361 
   363     if (LoadTracks (cdrom) < 0)
   362     if (LoadTracks(cdrom) < 0)
   364         return -2;
   363         return -2;
   365 
   364 
   366     if (PauseFile () < 0)
   365     if (PauseFile() < 0)
   367         return -3;
   366         return -3;
   368 
   367 
   369     if (ReleaseFile () < 0)
   368     if (ReleaseFile() < 0)
   370         return -4;
   369         return -4;
   371 
   370 
   372     ref = GetFileForOffset (cdrom, start, length, &startFrame, &stopFrame);
   371     ref = GetFileForOffset(cdrom, start, length, &startFrame, &stopFrame);
   373     if (ref == NULL) {
   372     if (ref == NULL) {
   374         SDL_SetError ("SDL_SYS_CDPlay: No file for start=%d, length=%d",
   373         SDL_SetError("SDL_SYS_CDPlay: No file for start=%d, length=%d",
   375                       start, length);
   374                      start, length);
   376         return -5;
   375         return -5;
   377     }
   376     }
   378 
   377 
   379     if (LoadFile (ref, startFrame, stopFrame) < 0)
   378     if (LoadFile(ref, startFrame, stopFrame) < 0)
   380         return -6;
   379         return -6;
   381 
   380 
   382     SetCompletionProc (CompletionProc, cdrom);
   381     SetCompletionProc(CompletionProc, cdrom);
   383 
   382 
   384     if (PlayFile () < 0)
   383     if (PlayFile() < 0)
   385         return -7;
   384         return -7;
   386 
   385 
   387     status = CD_PLAYING;
   386     status = CD_PLAYING;
   388 
   387 
   389     Unlock ();
   388     Unlock();
   390 
   389 
   391     return 0;
   390     return 0;
   392 }
   391 }
   393 
   392 
   394 /* Pause playback */
   393 /* Pause playback */
   395 static int
   394 static int
   396 SDL_SYS_CDPause (SDL_CD * cdrom)
   395 SDL_SYS_CDPause(SDL_CD * cdrom)
   397 {
   396 {
   398     if (fakeCD) {
   397     if (fakeCD) {
   399         SDL_SetError (kErrorFakeDevice);
   398         SDL_SetError(kErrorFakeDevice);
   400         return -1;
   399         return -1;
   401     }
   400     }
   402 
   401 
   403     Lock ();
   402     Lock();
   404 
   403 
   405     if (PauseFile () < 0) {
   404     if (PauseFile() < 0) {
   406         Unlock ();
   405         Unlock();
   407         return -2;
   406         return -2;
   408     }
   407     }
   409 
   408 
   410     status = CD_PAUSED;
   409     status = CD_PAUSED;
   411 
   410 
   412     Unlock ();
   411     Unlock();
   413 
   412 
   414     return 0;
   413     return 0;
   415 }
   414 }
   416 
   415 
   417 /* Resume playback */
   416 /* Resume playback */
   418 static int
   417 static int
   419 SDL_SYS_CDResume (SDL_CD * cdrom)
   418 SDL_SYS_CDResume(SDL_CD * cdrom)
   420 {
   419 {
   421     if (fakeCD) {
   420     if (fakeCD) {
   422         SDL_SetError (kErrorFakeDevice);
   421         SDL_SetError(kErrorFakeDevice);
   423         return -1;
   422         return -1;
   424     }
   423     }
   425 
   424 
   426     Lock ();
   425     Lock();
   427 
   426 
   428     if (PlayFile () < 0) {
   427     if (PlayFile() < 0) {
   429         Unlock ();
   428         Unlock();
   430         return -2;
   429         return -2;
   431     }
   430     }
   432 
   431 
   433     status = CD_PLAYING;
   432     status = CD_PLAYING;
   434 
   433 
   435     Unlock ();
   434     Unlock();
   436 
   435 
   437     return 0;
   436     return 0;
   438 }
   437 }
   439 
   438 
   440 /* Stop playback */
   439 /* Stop playback */
   441 static int
   440 static int
   442 SDL_SYS_CDStop (SDL_CD * cdrom)
   441 SDL_SYS_CDStop(SDL_CD * cdrom)
   443 {
   442 {
   444     if (fakeCD) {
   443     if (fakeCD) {
   445         SDL_SetError (kErrorFakeDevice);
   444         SDL_SetError(kErrorFakeDevice);
   446         return -1;
   445         return -1;
   447     }
   446     }
   448 
   447 
   449     Lock ();
   448     Lock();
   450 
   449 
   451     if (PauseFile () < 0) {
   450     if (PauseFile() < 0) {
   452         Unlock ();
   451         Unlock();
   453         return -2;
   452         return -2;
   454     }
   453     }
   455 
   454 
   456     if (ReleaseFile () < 0) {
   455     if (ReleaseFile() < 0) {
   457         Unlock ();
   456         Unlock();
   458         return -3;
   457         return -3;
   459     }
   458     }
   460 
   459 
   461     status = CD_STOPPED;
   460     status = CD_STOPPED;
   462 
   461 
   463     Unlock ();
   462     Unlock();
   464 
   463 
   465     return 0;
   464     return 0;
   466 }
   465 }
   467 
   466 
   468 /* Eject the CD-ROM (Unmount the volume) */
   467 /* Eject the CD-ROM (Unmount the volume) */
   469 static int
   468 static int
   470 SDL_SYS_CDEject (SDL_CD * cdrom)
   469 SDL_SYS_CDEject(SDL_CD * cdrom)
   471 {
   470 {
   472     OSStatus err;
   471     OSStatus err;
   473     pid_t dissenter;
   472     pid_t dissenter;
   474 
   473 
   475     if (fakeCD) {
   474     if (fakeCD) {
   476         SDL_SetError (kErrorFakeDevice);
   475         SDL_SetError(kErrorFakeDevice);
   477         return -1;
   476         return -1;
   478     }
   477     }
   479 
   478 
   480     Lock ();
   479     Lock();
   481 
   480 
   482     if (PauseFile () < 0) {
   481     if (PauseFile() < 0) {
   483         Unlock ();
   482         Unlock();
   484         return -2;
   483         return -2;
   485     }
   484     }
   486 
   485 
   487     if (ReleaseFile () < 0) {
   486     if (ReleaseFile() < 0) {
   488         Unlock ();
   487         Unlock();
   489         return -3;
   488         return -3;
   490     }
   489     }
   491 
   490 
   492     status = CD_STOPPED;
   491     status = CD_STOPPED;
   493 
   492 
   494     /* Eject the volume */
   493     /* Eject the volume */
   495     err = FSEjectVolumeSync (volumes[cdrom->id], kNilOptions, &dissenter);
   494     err = FSEjectVolumeSync(volumes[cdrom->id], kNilOptions, &dissenter);
   496 
   495 
   497     if (err != noErr) {
   496     if (err != noErr) {
   498         Unlock ();
   497         Unlock();
   499         SDL_SetError ("PBUnmountVol returned %d", err);
   498         SDL_SetError("PBUnmountVol returned %d", err);
   500         return -4;
   499         return -4;
   501     }
   500     }
   502 
   501 
   503     status = CD_TRAYEMPTY;
   502     status = CD_TRAYEMPTY;
   504 
   503 
   505     /* Invalidate volume and track info */
   504     /* Invalidate volume and track info */
   506     volumes[cdrom->id] = 0;
   505     volumes[cdrom->id] = 0;
   507     free (tracks[cdrom->id]);
   506     free(tracks[cdrom->id]);
   508     tracks[cdrom->id] = NULL;
   507     tracks[cdrom->id] = NULL;
   509 
   508 
   510     Unlock ();
   509     Unlock();
   511 
   510 
   512     return 0;
   511     return 0;
   513 }
   512 }
   514 
   513 
   515 /* Close the CD-ROM */
   514 /* Close the CD-ROM */
   516 static void
   515 static void
   517 SDL_SYS_CDClose (SDL_CD * cdrom)
   516 SDL_SYS_CDClose(SDL_CD * cdrom)
   518 {
   517 {
   519     currentDrive = -1;
   518     currentDrive = -1;
   520     return;
   519     return;
   521 }
   520 }
   522 
   521