* Moved cdda_text test application to the test directory, and separated it from cdda.cpp.
* Implemented most of the directory retrieval functions of the file system; even renaming titles should work now. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21139 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
d0b38183fd
commit
40897d3964
@ -6,8 +6,5 @@ UsePrivateHeaders [ FDirName storage ] ;
|
||||
|
||||
KernelAddon cdda :
|
||||
kernel_interface.cpp
|
||||
;
|
||||
|
||||
SimpleTest cdda_text :
|
||||
cdda.cpp
|
||||
: be ;
|
||||
;
|
||||
|
@ -4,17 +4,15 @@
|
||||
*/
|
||||
|
||||
|
||||
#include <bus/scsi/scsi_cmds.h>
|
||||
#include "cdda.h"
|
||||
|
||||
#include <KernelExport.h>
|
||||
#include <device/scsi.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define kFramesPerSecond 75
|
||||
#define kFramesPerMinute (kFramesPerSecond * 60)
|
||||
|
||||
struct cdtext_pack_data {
|
||||
uint8 id;
|
||||
@ -27,35 +25,37 @@ struct cdtext_pack_data {
|
||||
uint8 crc[2];
|
||||
} _PACKED;
|
||||
|
||||
|
||||
static const uint8 kMaxTracks = 0x63;
|
||||
enum {
|
||||
kTrackID = 0x80,
|
||||
kArtistID = 0x81,
|
||||
kMessageID = 0x85,
|
||||
};
|
||||
|
||||
struct cdtext {
|
||||
char *artist;
|
||||
char *album;
|
||||
char *titles[kMaxTracks];
|
||||
char *artists[kMaxTracks];
|
||||
uint8 track_count;
|
||||
char *genre;
|
||||
};
|
||||
static const uint32 kBufferSize = 16384;
|
||||
static const uint32 kSenseSize = 1024;
|
||||
|
||||
|
||||
// #pragma mark - string functions
|
||||
|
||||
|
||||
bool
|
||||
static char *
|
||||
copy_string(const char *string)
|
||||
{
|
||||
if (string == NULL || !string[0])
|
||||
return NULL;
|
||||
|
||||
return strdup(string);
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
is_garbage(char c)
|
||||
{
|
||||
return isspace(c) || c == '-' || c == '/' || c == '\\';
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
static void
|
||||
sanitize_string(char *string)
|
||||
{
|
||||
if (string == NULL)
|
||||
@ -106,7 +106,7 @@ find_string(const char *string, const char *find)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
static void
|
||||
cut_string(char *string, char *cut)
|
||||
{
|
||||
if (string == NULL || cut == NULL)
|
||||
@ -121,7 +121,7 @@ cut_string(char *string, char *cut)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
static void
|
||||
sanitize_album(cdtext &text)
|
||||
{
|
||||
cut_string(text.album, text.artist);
|
||||
@ -133,7 +133,7 @@ sanitize_album(cdtext &text)
|
||||
if (space != NULL) {
|
||||
space[0] = '\0';
|
||||
text.artist = text.album;
|
||||
text.album = strdup(space + 2);
|
||||
text.album = copy_string(space + 2);
|
||||
|
||||
sanitize_string(text.artist);
|
||||
sanitize_string(text.album);
|
||||
@ -142,26 +142,28 @@ sanitize_album(cdtext &text)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
static void
|
||||
sanitize_titles(cdtext &text)
|
||||
{
|
||||
for (uint8 i = 0; i < text.track_count; i++) {
|
||||
cut_string(text.titles[i], "(Album Version)");
|
||||
sanitize_string(text.titles[i]);
|
||||
sanitize_string(text.artists[i]);
|
||||
if (!strcasecmp(text.artists[i], text.artist)) {
|
||||
|
||||
if (text.artists[i] != NULL && text.artist != NULL
|
||||
&& !strcasecmp(text.artists[i], text.artist)) {
|
||||
// if the title artist is the same as the main artist, remove it
|
||||
free(text.artists[i]);
|
||||
text.artists[i] = NULL;
|
||||
}
|
||||
|
||||
if (text.titles[i] != NULL && text.titles[i][0] == '\t' && i > 0)
|
||||
text.titles[i] = strdup(text.titles[i - 1]);
|
||||
text.titles[i] = copy_string(text.titles[i - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
static bool
|
||||
single_case(const char *string, bool &upper, bool &first)
|
||||
{
|
||||
if (string == NULL)
|
||||
@ -185,7 +187,7 @@ single_case(const char *string, bool &upper, bool &first)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
static void
|
||||
capitalize_string(char *string)
|
||||
{
|
||||
if (string == NULL)
|
||||
@ -207,7 +209,7 @@ capitalize_string(char *string)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
static void
|
||||
correct_case(cdtext &text)
|
||||
{
|
||||
// check if all titles share a single case
|
||||
@ -238,14 +240,39 @@ correct_case(cdtext &text)
|
||||
// #pragma mark - CD-Text
|
||||
|
||||
|
||||
bool
|
||||
cdtext::cdtext()
|
||||
:
|
||||
artist(NULL),
|
||||
album(NULL),
|
||||
genre(NULL),
|
||||
track_count(0)
|
||||
{
|
||||
memset(titles, 0, sizeof(titles));
|
||||
memset(artists, 0, sizeof(artists));
|
||||
}
|
||||
|
||||
|
||||
cdtext::~cdtext()
|
||||
{
|
||||
free(album);
|
||||
free(artist);
|
||||
free(genre);
|
||||
|
||||
for (uint8 i = 0; i < track_count; i++) {
|
||||
free(titles[i]);
|
||||
free(artists[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
is_string_id(uint8 id)
|
||||
{
|
||||
return id >= kTrackID && id <= kMessageID;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
static bool
|
||||
parse_pack_data(cdtext_pack_data *&pack, uint32 &packLeft,
|
||||
cdtext_pack_data *&lastPack, uint8 &id, uint8 &track, uint8 &state,
|
||||
char *buffer, size_t &length)
|
||||
@ -280,13 +307,13 @@ parse_pack_data(cdtext_pack_data *&pack, uint32 &packLeft,
|
||||
|
||||
while (id == pack->id && track == pack->track) {
|
||||
#if 1
|
||||
printf("%u.%u.%u, %u.%u.%u, ", pack->id, pack->track, pack->number,
|
||||
dprintf("%u.%u.%u, %u.%u.%u, ", pack->id, pack->track, pack->number,
|
||||
pack->double_byte, pack->block_number, pack->character_position);
|
||||
for (int32 i = 0; i < 12; i++) {
|
||||
if (isprint(pack->text[i]))
|
||||
putchar(pack->text[i]);
|
||||
dprintf("%c", pack->text[i]);
|
||||
}
|
||||
putchar('\n');
|
||||
dprintf("\n");
|
||||
#endif
|
||||
if (is_string_id(id)) {
|
||||
// TODO: support double byte characters
|
||||
@ -330,72 +357,22 @@ parse_pack_data(cdtext_pack_data *&pack, uint32 &packLeft,
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
dump_cdtext(cdtext_pack_data *pack, size_t packLength)
|
||||
static void
|
||||
dump_cdtext(cdtext &text)
|
||||
{
|
||||
cdtext_pack_data *lastPack = NULL;
|
||||
char buffer[256];
|
||||
uint8 state = 0;
|
||||
cdtext text;
|
||||
|
||||
memset(&text, 0, sizeof(cdtext));
|
||||
|
||||
while (true) {
|
||||
size_t length = sizeof(buffer);
|
||||
uint8 id, track;
|
||||
|
||||
if (!parse_pack_data(pack, packLength, lastPack, id, track,
|
||||
state, buffer, length))
|
||||
break;
|
||||
|
||||
switch (id) {
|
||||
case kTrackID:
|
||||
if (track == 0) {
|
||||
if (text.album == NULL)
|
||||
text.album = strdup(buffer);
|
||||
} else if (track <= kMaxTracks) {
|
||||
if (text.titles[track - 1] == NULL)
|
||||
text.titles[track - 1] = strdup(buffer);
|
||||
if (track > text.track_count)
|
||||
text.track_count = track;
|
||||
}
|
||||
break;
|
||||
|
||||
case kArtistID:
|
||||
if (track == 0) {
|
||||
if (text.artist == NULL)
|
||||
text.artist = strdup(buffer);
|
||||
} else if (track <= kMaxTracks) {
|
||||
if (text.artists[track - 1] == NULL)
|
||||
text.artists[track - 1] = strdup(buffer);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (is_string_id(id))
|
||||
printf("UNKNOWN %u: \"%s\"\n", id, buffer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sanitize_string(text.artist);
|
||||
sanitize_album(text);
|
||||
sanitize_titles(text);
|
||||
correct_case(text);
|
||||
|
||||
if (text.album)
|
||||
printf("Album: \"%s\"\n", text.album);
|
||||
dprintf("Album: \"%s\"\n", text.album);
|
||||
if (text.artist)
|
||||
printf("Artist: \"%s\"\n", text.artist);
|
||||
dprintf("Artist: \"%s\"\n", text.artist);
|
||||
for (uint8 i = 0; i < text.track_count; i++) {
|
||||
printf("Track %02u: \"%s\"%s%s%s\n", i + 1, text.titles[i],
|
||||
dprintf("Track %02u: \"%s\"%s%s%s\n", i + 1, text.titles[i],
|
||||
text.artists[i] ? " (" : "", text.artists[i] ? text.artists[i] : "",
|
||||
text.artists[i] ? ")" : "");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
static void
|
||||
dump_toc(scsi_toc_toc *toc)
|
||||
{
|
||||
int32 numTracks = toc->last_track + 1 - toc->first_track;
|
||||
@ -415,22 +392,24 @@ dump_toc(scsi_toc_toc *toc)
|
||||
length.second = (diff % kFramesPerMinute) / kFramesPerSecond;
|
||||
length.frame = diff % kFramesPerSecond;
|
||||
|
||||
printf("%02u. %02u:%02u.%02u (length %02u:%02u.%02u)\n",
|
||||
dprintf("%02u. %02u:%02u.%02u (length %02u:%02u.%02u)\n",
|
||||
track.track_number, start.minute, start.second, start.frame,
|
||||
length.minute, length.second, length.frame);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
static status_t
|
||||
read_table_of_contents(int fd, uint32 track, uint8 format, uint8 *buffer,
|
||||
size_t bufferSize)
|
||||
{
|
||||
raw_device_command raw;
|
||||
uint8 senseData[1024];
|
||||
uint8 *senseData = (uint8 *)malloc(kSenseSize);
|
||||
if (senseData == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
memset(&raw, 0, sizeof(raw_device_command));
|
||||
memset(senseData, 0, sizeof(senseData));
|
||||
memset(senseData, 0, kSenseSize);
|
||||
memset(buffer, 0, bufferSize);
|
||||
|
||||
scsi_cmd_read_toc &toc = *(scsi_cmd_read_toc*)&raw.command;
|
||||
@ -449,84 +428,106 @@ read_table_of_contents(int fd, uint32 track, uint8 format, uint8 *buffer,
|
||||
raw.data_length = bufferSize;
|
||||
raw.timeout = 10000000LL; // 10 secs
|
||||
raw.sense_data = senseData;
|
||||
raw.sense_data_length = sizeof(senseData);
|
||||
raw.sense_data_length = sizeof(kSenseSize);
|
||||
|
||||
if (ioctl(fd, B_RAW_DEVICE_COMMAND, &raw) == 0) {
|
||||
if (raw.scsi_status == 0 && raw.cam_status == 1) {
|
||||
puts("success!\n");
|
||||
} else {
|
||||
puts("failure!\n");
|
||||
}
|
||||
if (ioctl(fd, B_RAW_DEVICE_COMMAND, &raw) == 0
|
||||
&& raw.scsi_status == 0 && raw.cam_status == 1) {
|
||||
free(senseData);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
return 0;
|
||||
free(senseData);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
dump_block(const uint8 *buffer, int size, const char *prefix)
|
||||
// #pragma mark - exported functions
|
||||
|
||||
|
||||
status_t
|
||||
read_cdtext(int fd, struct cdtext &cdtext)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < size;)
|
||||
{
|
||||
int start = i;
|
||||
uint8 *buffer = (uint8 *)malloc(kBufferSize);
|
||||
if (buffer == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
printf(prefix);
|
||||
for (; i < start+16; i++)
|
||||
{
|
||||
if (!(i % 4))
|
||||
printf(" ");
|
||||
|
||||
if (i >= size)
|
||||
printf(" ");
|
||||
else
|
||||
printf("%02x", *(unsigned char *)(buffer + i));
|
||||
}
|
||||
printf(" ");
|
||||
|
||||
for (i = start; i < start + 16; i++)
|
||||
{
|
||||
if (i < size)
|
||||
{
|
||||
char c = buffer[i];
|
||||
|
||||
if (c < 30)
|
||||
printf(".");
|
||||
else
|
||||
printf("%c", c);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
printf("\n");
|
||||
// do it twice, just in case...
|
||||
// (at least my CD-ROM sometimes returned broken data on first try)
|
||||
read_table_of_contents(fd, 1, SCSI_TOC_FORMAT_CD_TEXT, buffer,
|
||||
kBufferSize);
|
||||
if (read_table_of_contents(fd, 1, SCSI_TOC_FORMAT_CD_TEXT, buffer,
|
||||
kBufferSize) < B_OK) {
|
||||
free(buffer);
|
||||
return B_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char** argv)
|
||||
{
|
||||
int fd = open(argv[1], O_RDONLY);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
uint8 buffer[1024];
|
||||
scsi_toc_general *header = (scsi_toc_general *)buffer;
|
||||
|
||||
read_table_of_contents(fd, 1, SCSI_TOC_FORMAT_TOC, buffer, sizeof(buffer));
|
||||
header->data_length = B_BENDIAN_TO_HOST_INT16(header->data_length);
|
||||
printf("TOC header %u, %d, %d\n", header->data_length, header->first, header->last);
|
||||
//dump_block(buffer, header->data_length + 2, "TOC");
|
||||
dump_toc((scsi_toc_toc *)buffer);
|
||||
size_t packLength = B_BENDIAN_TO_HOST_INT16(header->data_length) - 2;
|
||||
cdtext_pack_data *pack = (cdtext_pack_data *)(header + 1);
|
||||
cdtext_pack_data *lastPack = NULL;
|
||||
uint8 state = 0;
|
||||
char text[256];
|
||||
|
||||
read_table_of_contents(fd, 1, SCSI_TOC_FORMAT_CD_TEXT, buffer, sizeof(buffer));
|
||||
read_table_of_contents(fd, 1, SCSI_TOC_FORMAT_CD_TEXT, buffer, sizeof(buffer));
|
||||
header->data_length = B_BENDIAN_TO_HOST_INT16(header->data_length);
|
||||
printf("TEXT header %u, %d, %d\n", header->data_length, header->first, header->last);
|
||||
//dump_block(buffer, header->data_length + 2, "TEXT");
|
||||
while (true) {
|
||||
size_t length = sizeof(text);
|
||||
uint8 id, track;
|
||||
|
||||
dump_cdtext((cdtext_pack_data *)(buffer + 4), header->data_length - 2);
|
||||
if (!parse_pack_data(pack, packLength, lastPack, id, track,
|
||||
state, text, length))
|
||||
break;
|
||||
|
||||
close(fd);
|
||||
switch (id) {
|
||||
case kTrackID:
|
||||
if (track == 0) {
|
||||
if (cdtext.album == NULL)
|
||||
cdtext.album = copy_string(text);
|
||||
} else if (track <= kMaxTracks) {
|
||||
if (cdtext.titles[track - 1] == NULL)
|
||||
cdtext.titles[track - 1] = copy_string(text);
|
||||
if (track > cdtext.track_count)
|
||||
cdtext.track_count = track;
|
||||
}
|
||||
break;
|
||||
|
||||
case kArtistID:
|
||||
if (track == 0) {
|
||||
if (cdtext.artist == NULL)
|
||||
cdtext.artist = copy_string(text);
|
||||
} else if (track <= kMaxTracks) {
|
||||
if (cdtext.artists[track - 1] == NULL)
|
||||
cdtext.artists[track - 1] = copy_string(text);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (is_string_id(id))
|
||||
dprintf("UNKNOWN %u: \"%s\"\n", id, text);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
|
||||
sanitize_string(cdtext.artist);
|
||||
sanitize_album(cdtext);
|
||||
sanitize_titles(cdtext);
|
||||
correct_case(cdtext);
|
||||
|
||||
dump_cdtext(cdtext);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
read_table_of_contents(int fd, scsi_toc_toc *toc, size_t length)
|
||||
{
|
||||
status_t status = read_table_of_contents(fd, 1, SCSI_TOC_FORMAT_TOC,
|
||||
(uint8*)toc, length);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
dump_toc(toc);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
34
src/add-ons/kernel/file_systems/cdda/cdda.h
Normal file
34
src/add-ons/kernel/file_systems/cdda/cdda.h
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2007, Axel Dörfler, axeld@pinc-software.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef CDDA_H
|
||||
#define CDDA_H
|
||||
|
||||
|
||||
#include <bus/scsi/scsi_cmds.h>
|
||||
|
||||
|
||||
static const uint32 kFramesPerSecond = 75;
|
||||
static const uint32 kFramesPerMinute = kFramesPerSecond * 60;
|
||||
static const uint32 kFrameSize = 2352;
|
||||
static const uint8 kMaxTracks = 0x63;
|
||||
|
||||
struct cdtext {
|
||||
cdtext();
|
||||
~cdtext();
|
||||
|
||||
char *artist;
|
||||
char *album;
|
||||
char *genre;
|
||||
|
||||
char *titles[kMaxTracks];
|
||||
char *artists[kMaxTracks];
|
||||
uint8 track_count;
|
||||
};
|
||||
|
||||
|
||||
status_t read_cdtext(int fd, cdtext &text);
|
||||
status_t read_table_of_contents(int fd, scsi_toc_toc *toc, size_t length);
|
||||
|
||||
#endif // CDDA_H
|
@ -4,6 +4,7 @@
|
||||
*/
|
||||
|
||||
|
||||
#include "cdda.h"
|
||||
#include "Lock.h"
|
||||
|
||||
#include <fs_info.h>
|
||||
@ -57,7 +58,8 @@ class Volume {
|
||||
off_t NumBlocks() const { return fNumBlocks; }
|
||||
|
||||
private:
|
||||
Inode *_CreateNode(Inode *parent, const char *name, int32 type);
|
||||
Inode *_CreateNode(Inode *parent, const char *name,
|
||||
off_t start, off_t frames, int32 type);
|
||||
|
||||
Semaphore fLock;
|
||||
int fDevice;
|
||||
@ -74,7 +76,8 @@ class Volume {
|
||||
|
||||
class Inode {
|
||||
public:
|
||||
Inode(Volume *volume, Inode *parent, const char *name, int32 type);
|
||||
Inode(Volume *volume, Inode *parent, const char *name, off_t start,
|
||||
off_t frames, int32 type);
|
||||
~Inode();
|
||||
|
||||
status_t InitCheck();
|
||||
@ -93,8 +96,12 @@ class Inode {
|
||||
{ return fCreationTime; }
|
||||
time_t ModificationTime() const
|
||||
{ return fModificationTime; }
|
||||
off_t StartFrame() const
|
||||
{ return fStartFrame; }
|
||||
off_t FrameCount() const
|
||||
{ return fFrameCount; }
|
||||
off_t Size() const
|
||||
{ return fSize; }
|
||||
{ return fFrameCount * kFrameSize /* + WAV header */; }
|
||||
|
||||
Inode *Next() const { return fNext; }
|
||||
void SetNext(Inode *inode) { fNext = inode; }
|
||||
@ -103,12 +110,13 @@ class Inode {
|
||||
Inode *fNext;
|
||||
vnode_id fID;
|
||||
int32 fType;
|
||||
const char *fName;
|
||||
char *fName;
|
||||
gid_t fGroupID;
|
||||
uid_t fUserID;
|
||||
time_t fCreationTime;
|
||||
time_t fModificationTime;
|
||||
off_t fSize;
|
||||
off_t fStartFrame;
|
||||
off_t fFrameCount;
|
||||
};
|
||||
|
||||
|
||||
@ -142,7 +150,7 @@ Volume::Volume(mount_id id)
|
||||
fFirstEntry(NULL)
|
||||
{
|
||||
// create the root vnode
|
||||
fRootNode = _CreateNode(NULL, "", S_IFDIR | 0777);
|
||||
fRootNode = _CreateNode(NULL, "", 0, 0, S_IFDIR | 0777);
|
||||
}
|
||||
|
||||
|
||||
@ -160,6 +168,8 @@ Volume::~Volume()
|
||||
next = inode->Next();
|
||||
delete inode;
|
||||
}
|
||||
|
||||
free(fName);
|
||||
}
|
||||
|
||||
|
||||
@ -181,6 +191,64 @@ Volume::Mount(const char* device)
|
||||
if (fDevice < 0)
|
||||
return errno;
|
||||
|
||||
scsi_toc_toc *toc = (scsi_toc_toc *)malloc(1024);
|
||||
if (toc == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
status_t status = read_table_of_contents(fDevice, toc, 1024);
|
||||
if (status < B_OK) {
|
||||
free(toc);
|
||||
return status;
|
||||
}
|
||||
|
||||
cdtext text;
|
||||
if (read_cdtext(fDevice, text) < B_OK)
|
||||
dprintf("CDDA: no CD-Text found.\n");
|
||||
|
||||
int32 trackCount = toc->last_track + 1 - toc->first_track;
|
||||
char title[256];
|
||||
|
||||
for (int32 i = 0; i < trackCount; i++) {
|
||||
scsi_cd_msf& next = toc->tracks[i + 1].start.time;
|
||||
// the last track is always lead-out
|
||||
scsi_cd_msf& start = toc->tracks[i].start.time;
|
||||
|
||||
off_t startFrame = start.minute * kFramesPerMinute
|
||||
+ start.second * kFramesPerSecond + start.frame;
|
||||
off_t frames = next.minute * kFramesPerMinute
|
||||
+ next.second * kFramesPerSecond + next.frame
|
||||
- startFrame;
|
||||
|
||||
if (text.titles[i] != NULL && text.titles[i]) {
|
||||
if (text.artists[i] != NULL && text.artists[i]) {
|
||||
snprintf(title, sizeof(title), "%02ld. %s - %s.wav", i + 1,
|
||||
text.artists[i], text.titles[i]);
|
||||
} else {
|
||||
snprintf(title, sizeof(title), "%02ld. %s.wav", i + 1,
|
||||
text.titles[i]);
|
||||
}
|
||||
} else
|
||||
snprintf(title, sizeof(title), "%02ld.wav", i + 1);
|
||||
|
||||
_CreateNode(fRootNode, title, startFrame, frames, S_IFREG | 0444);
|
||||
}
|
||||
|
||||
free(toc);
|
||||
|
||||
// determine volume title
|
||||
|
||||
if (text.artist != NULL && text.album != NULL)
|
||||
snprintf(title, sizeof(title), "%s - %s", text.artist, text.album);
|
||||
else if (text.artist != NULL || text.album != NULL) {
|
||||
snprintf(title, sizeof(title), "%s", text.artist != NULL
|
||||
? text.artist : text.album);
|
||||
} else
|
||||
strcpy(title, "Audio CD");
|
||||
|
||||
fName = strdup(title);
|
||||
if (fName == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@ -193,9 +261,10 @@ Volume::Lock()
|
||||
|
||||
|
||||
Inode *
|
||||
Volume::_CreateNode(Inode *parent, const char *name, int32 type)
|
||||
Volume::_CreateNode(Inode *parent, const char *name, off_t start, off_t frames,
|
||||
int32 type)
|
||||
{
|
||||
Inode *inode = new Inode(this, parent, name, type);
|
||||
Inode *inode = new Inode(this, parent, name, start, frames, type);
|
||||
if (inode == NULL)
|
||||
return NULL;
|
||||
|
||||
@ -245,14 +314,24 @@ Volume::Find(const char *name)
|
||||
status_t
|
||||
Volume::SetName(const char *name)
|
||||
{
|
||||
return B_ERROR;
|
||||
if (name == NULL || !name[0])
|
||||
return B_BAD_VALUE;
|
||||
|
||||
name = strdup(name);
|
||||
if (name == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
free(fName);
|
||||
fName = (char *)name;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
Inode::Inode(Volume *volume, Inode *parent, const char *name, int32 type)
|
||||
Inode::Inode(Volume *volume, Inode *parent, const char *name, off_t start,
|
||||
off_t frames, int32 type)
|
||||
:
|
||||
fNext(NULL)
|
||||
{
|
||||
@ -262,6 +341,8 @@ Inode::Inode(Volume *volume, Inode *parent, const char *name, int32 type)
|
||||
|
||||
fID = volume->GetNextNodeID();
|
||||
fType = type;
|
||||
fStartFrame = start;
|
||||
fFrameCount = frames;
|
||||
|
||||
fUserID = geteuid();
|
||||
fGroupID = parent ? parent->GroupID() : getegid();
|
||||
@ -289,7 +370,16 @@ Inode::InitCheck()
|
||||
status_t
|
||||
Inode::SetName(const char* name)
|
||||
{
|
||||
return B_ERROR;
|
||||
if (name == NULL || !name[0])
|
||||
return B_BAD_VALUE;
|
||||
|
||||
name = strdup(name);
|
||||
if (name == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
free(fName);
|
||||
fName = (char *)name;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
@ -578,7 +668,19 @@ cdda_rename(fs_volume _volume, void *_oldDir, const char *oldName, void *_newDir
|
||||
|| strchr(newName, '/') != NULL)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
return B_ERROR;
|
||||
// we only have a single directory which simplifies things a bit :-)
|
||||
|
||||
Volume *volume = (Volume *)_volume;
|
||||
Locker _(volume->Lock());
|
||||
|
||||
Inode *inode = volume->Find(oldName);
|
||||
if (inode == NULL)
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
|
||||
if (volume->Find(newName) != NULL)
|
||||
return B_NAME_IN_USE;
|
||||
|
||||
return inode->SetName(newName);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
SubDir HAIKU_TOP src tests add-ons kernel file_systems ;
|
||||
|
||||
SubInclude HAIKU_TOP src tests add-ons kernel file_systems bfs ;
|
||||
SubInclude HAIKU_TOP src tests add-ons kernel file_systems cdda ;
|
||||
SubInclude HAIKU_TOP src tests add-ons kernel file_systems fs_shell ;
|
||||
#SubInclude HAIKU_TOP src tests add-ons kernel file_systems iso9660 ;
|
||||
SubInclude HAIKU_TOP src tests add-ons kernel file_systems udf ;
|
||||
|
9
src/tests/add-ons/kernel/file_systems/cdda/Jamfile
Normal file
9
src/tests/add-ons/kernel/file_systems/cdda/Jamfile
Normal file
@ -0,0 +1,9 @@
|
||||
SubDir HAIKU_TOP src tests add-ons kernel file_systems cdda ;
|
||||
|
||||
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src add-ons kernel file_systems cdda ] ;
|
||||
|
||||
SimpleTest cdda_text
|
||||
:
|
||||
cdda_text.cpp
|
||||
cdda.cpp
|
||||
;
|
48
src/tests/add-ons/kernel/file_systems/cdda/cdda_text.cpp
Normal file
48
src/tests/add-ons/kernel/file_systems/cdda/cdda_text.cpp
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2007, Axel Dörfler, axeld@pinc-software.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "cdda.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
extern const char* __progname;
|
||||
|
||||
|
||||
extern "C" void
|
||||
dprintf(const char* format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vprintf(format, args);
|
||||
fflush(stdout);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char** argv)
|
||||
{
|
||||
if (argc < 2)
|
||||
return -1;
|
||||
int fd = open(argv[1], O_RDONLY);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
uint8 buffer[1024];
|
||||
if (read_table_of_contents(fd, (scsi_toc_toc*)buffer, sizeof(buffer)) < 0) {
|
||||
fprintf(stderr, "%s: Retrieving TOC failed", __progname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
cdtext text;
|
||||
read_cdtext(fd, text);
|
||||
|
||||
close(fd);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user