* 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:
Axel Dörfler
2007-05-15 00:51:35 +00:00
parent d0b38183fd
commit 40897d3964
7 changed files with 364 additions and 172 deletions
+1 -4
View File
@@ -6,8 +6,5 @@ UsePrivateHeaders [ FDirName storage ] ;
KernelAddon cdda : KernelAddon cdda :
kernel_interface.cpp kernel_interface.cpp
;
SimpleTest cdda_text :
cdda.cpp cdda.cpp
: be ; ;
+157 -156
View File
@@ -4,17 +4,15 @@
*/ */
#include <bus/scsi/scsi_cmds.h> #include "cdda.h"
#include <KernelExport.h>
#include <device/scsi.h> #include <device/scsi.h>
#include <ctype.h> #include <ctype.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h>
#define kFramesPerSecond 75
#define kFramesPerMinute (kFramesPerSecond * 60)
struct cdtext_pack_data { struct cdtext_pack_data {
uint8 id; uint8 id;
@@ -27,35 +25,37 @@ struct cdtext_pack_data {
uint8 crc[2]; uint8 crc[2];
} _PACKED; } _PACKED;
static const uint8 kMaxTracks = 0x63;
enum { enum {
kTrackID = 0x80, kTrackID = 0x80,
kArtistID = 0x81, kArtistID = 0x81,
kMessageID = 0x85, kMessageID = 0x85,
}; };
struct cdtext { static const uint32 kBufferSize = 16384;
char *artist; static const uint32 kSenseSize = 1024;
char *album;
char *titles[kMaxTracks];
char *artists[kMaxTracks];
uint8 track_count;
char *genre;
};
// #pragma mark - string functions // #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) is_garbage(char c)
{ {
return isspace(c) || c == '-' || c == '/' || c == '\\'; return isspace(c) || c == '-' || c == '/' || c == '\\';
} }
void static void
sanitize_string(char *string) sanitize_string(char *string)
{ {
if (string == NULL) if (string == NULL)
@@ -106,7 +106,7 @@ find_string(const char *string, const char *find)
} }
void static void
cut_string(char *string, char *cut) cut_string(char *string, char *cut)
{ {
if (string == NULL || cut == NULL) if (string == NULL || cut == NULL)
@@ -121,7 +121,7 @@ cut_string(char *string, char *cut)
} }
void static void
sanitize_album(cdtext &text) sanitize_album(cdtext &text)
{ {
cut_string(text.album, text.artist); cut_string(text.album, text.artist);
@@ -133,7 +133,7 @@ sanitize_album(cdtext &text)
if (space != NULL) { if (space != NULL) {
space[0] = '\0'; space[0] = '\0';
text.artist = text.album; text.artist = text.album;
text.album = strdup(space + 2); text.album = copy_string(space + 2);
sanitize_string(text.artist); sanitize_string(text.artist);
sanitize_string(text.album); sanitize_string(text.album);
@@ -142,26 +142,28 @@ sanitize_album(cdtext &text)
} }
void static void
sanitize_titles(cdtext &text) sanitize_titles(cdtext &text)
{ {
for (uint8 i = 0; i < text.track_count; i++) { for (uint8 i = 0; i < text.track_count; i++) {
cut_string(text.titles[i], "(Album Version)"); cut_string(text.titles[i], "(Album Version)");
sanitize_string(text.titles[i]); sanitize_string(text.titles[i]);
sanitize_string(text.artists[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 // if the title artist is the same as the main artist, remove it
free(text.artists[i]); free(text.artists[i]);
text.artists[i] = NULL; text.artists[i] = NULL;
} }
if (text.titles[i] != NULL && text.titles[i][0] == '\t' && i > 0) 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) single_case(const char *string, bool &upper, bool &first)
{ {
if (string == NULL) if (string == NULL)
@@ -185,7 +187,7 @@ single_case(const char *string, bool &upper, bool &first)
} }
void static void
capitalize_string(char *string) capitalize_string(char *string)
{ {
if (string == NULL) if (string == NULL)
@@ -207,7 +209,7 @@ capitalize_string(char *string)
} }
void static void
correct_case(cdtext &text) correct_case(cdtext &text)
{ {
// check if all titles share a single case // check if all titles share a single case
@@ -238,14 +240,39 @@ correct_case(cdtext &text)
// #pragma mark - CD-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) is_string_id(uint8 id)
{ {
return id >= kTrackID && id <= kMessageID; return id >= kTrackID && id <= kMessageID;
} }
bool static bool
parse_pack_data(cdtext_pack_data *&pack, uint32 &packLeft, parse_pack_data(cdtext_pack_data *&pack, uint32 &packLeft,
cdtext_pack_data *&lastPack, uint8 &id, uint8 &track, uint8 &state, cdtext_pack_data *&lastPack, uint8 &id, uint8 &track, uint8 &state,
char *buffer, size_t &length) 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) { while (id == pack->id && track == pack->track) {
#if 1 #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); pack->double_byte, pack->block_number, pack->character_position);
for (int32 i = 0; i < 12; i++) { for (int32 i = 0; i < 12; i++) {
if (isprint(pack->text[i])) if (isprint(pack->text[i]))
putchar(pack->text[i]); dprintf("%c", pack->text[i]);
} }
putchar('\n'); dprintf("\n");
#endif #endif
if (is_string_id(id)) { if (is_string_id(id)) {
// TODO: support double byte characters // TODO: support double byte characters
@@ -330,72 +357,22 @@ parse_pack_data(cdtext_pack_data *&pack, uint32 &packLeft,
} }
void static void
dump_cdtext(cdtext_pack_data *pack, size_t packLength) 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) if (text.album)
printf("Album: \"%s\"\n", text.album); dprintf("Album: \"%s\"\n", text.album);
if (text.artist) if (text.artist)
printf("Artist: \"%s\"\n", text.artist); dprintf("Artist: \"%s\"\n", text.artist);
for (uint8 i = 0; i < text.track_count; i++) { 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] ? " (" : "", text.artists[i] ? text.artists[i] : "",
text.artists[i] ? ")" : ""); text.artists[i] ? ")" : "");
} }
} }
void static void
dump_toc(scsi_toc_toc *toc) dump_toc(scsi_toc_toc *toc)
{ {
int32 numTracks = toc->last_track + 1 - toc->first_track; 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.second = (diff % kFramesPerMinute) / kFramesPerSecond;
length.frame = diff % 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, track.track_number, start.minute, start.second, start.frame,
length.minute, length.second, length.frame); length.minute, length.second, length.frame);
} }
} }
status_t static status_t
read_table_of_contents(int fd, uint32 track, uint8 format, uint8 *buffer, read_table_of_contents(int fd, uint32 track, uint8 format, uint8 *buffer,
size_t bufferSize) size_t bufferSize)
{ {
raw_device_command raw; 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(&raw, 0, sizeof(raw_device_command));
memset(senseData, 0, sizeof(senseData)); memset(senseData, 0, kSenseSize);
memset(buffer, 0, bufferSize); memset(buffer, 0, bufferSize);
scsi_cmd_read_toc &toc = *(scsi_cmd_read_toc*)&raw.command; 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.data_length = bufferSize;
raw.timeout = 10000000LL; // 10 secs raw.timeout = 10000000LL; // 10 secs
raw.sense_data = senseData; 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 (ioctl(fd, B_RAW_DEVICE_COMMAND, &raw) == 0
if (raw.scsi_status == 0 && raw.cam_status == 1) { && raw.scsi_status == 0 && raw.cam_status == 1) {
puts("success!\n"); free(senseData);
} else { return B_OK;
puts("failure!\n");
}
} }
return 0; free(senseData);
return B_ERROR;
} }
void // #pragma mark - exported functions
dump_block(const uint8 *buffer, int size, const char *prefix)
status_t
read_cdtext(int fd, struct cdtext &cdtext)
{ {
int i; uint8 *buffer = (uint8 *)malloc(kBufferSize);
if (buffer == NULL)
for (i = 0; i < size;) return B_NO_MEMORY;
{
int start = i;
printf(prefix); // do it twice, just in case...
for (; i < start+16; i++) // (at least my CD-ROM sometimes returned broken data on first try)
{ read_table_of_contents(fd, 1, SCSI_TOC_FORMAT_CD_TEXT, buffer,
if (!(i % 4)) kBufferSize);
printf(" "); if (read_table_of_contents(fd, 1, SCSI_TOC_FORMAT_CD_TEXT, buffer,
kBufferSize) < B_OK) {
if (i >= size) free(buffer);
printf(" "); return B_ERROR;
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");
} }
}
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; scsi_toc_general *header = (scsi_toc_general *)buffer;
read_table_of_contents(fd, 1, SCSI_TOC_FORMAT_TOC, buffer, sizeof(buffer)); size_t packLength = B_BENDIAN_TO_HOST_INT16(header->data_length) - 2;
header->data_length = B_BENDIAN_TO_HOST_INT16(header->data_length); cdtext_pack_data *pack = (cdtext_pack_data *)(header + 1);
printf("TOC header %u, %d, %d\n", header->data_length, header->first, header->last); cdtext_pack_data *lastPack = NULL;
//dump_block(buffer, header->data_length + 2, "TOC"); uint8 state = 0;
dump_toc((scsi_toc_toc *)buffer); char text[256];
read_table_of_contents(fd, 1, SCSI_TOC_FORMAT_CD_TEXT, buffer, sizeof(buffer)); while (true) {
read_table_of_contents(fd, 1, SCSI_TOC_FORMAT_CD_TEXT, buffer, sizeof(buffer)); size_t length = sizeof(text);
header->data_length = B_BENDIAN_TO_HOST_INT16(header->data_length); uint8 id, track;
printf("TEXT header %u, %d, %d\n", header->data_length, header->first, header->last);
//dump_block(buffer, header->data_length + 2, "TEXT");
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;
}
@@ -0,0 +1,34 @@
/*
* Copyright 2007, Axel Dörfler, [email protected].
* 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 "Lock.h"
#include <fs_info.h> #include <fs_info.h>
@@ -57,7 +58,8 @@ class Volume {
off_t NumBlocks() const { return fNumBlocks; } off_t NumBlocks() const { return fNumBlocks; }
private: 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; Semaphore fLock;
int fDevice; int fDevice;
@@ -74,7 +76,8 @@ class Volume {
class Inode { class Inode {
public: 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(); ~Inode();
status_t InitCheck(); status_t InitCheck();
@@ -93,8 +96,12 @@ class Inode {
{ return fCreationTime; } { return fCreationTime; }
time_t ModificationTime() const time_t ModificationTime() const
{ return fModificationTime; } { return fModificationTime; }
off_t StartFrame() const
{ return fStartFrame; }
off_t FrameCount() const
{ return fFrameCount; }
off_t Size() const off_t Size() const
{ return fSize; } { return fFrameCount * kFrameSize /* + WAV header */; }
Inode *Next() const { return fNext; } Inode *Next() const { return fNext; }
void SetNext(Inode *inode) { fNext = inode; } void SetNext(Inode *inode) { fNext = inode; }
@@ -103,12 +110,13 @@ class Inode {
Inode *fNext; Inode *fNext;
vnode_id fID; vnode_id fID;
int32 fType; int32 fType;
const char *fName; char *fName;
gid_t fGroupID; gid_t fGroupID;
uid_t fUserID; uid_t fUserID;
time_t fCreationTime; time_t fCreationTime;
time_t fModificationTime; time_t fModificationTime;
off_t fSize; off_t fStartFrame;
off_t fFrameCount;
}; };
@@ -142,7 +150,7 @@ Volume::Volume(mount_id id)
fFirstEntry(NULL) fFirstEntry(NULL)
{ {
// create the root vnode // 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(); next = inode->Next();
delete inode; delete inode;
} }
free(fName);
} }
@@ -181,6 +191,64 @@ Volume::Mount(const char* device)
if (fDevice < 0) if (fDevice < 0)
return errno; 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; return B_OK;
} }
@@ -193,9 +261,10 @@ Volume::Lock()
Inode * 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) if (inode == NULL)
return NULL; return NULL;
@@ -245,14 +314,24 @@ Volume::Find(const char *name)
status_t status_t
Volume::SetName(const char *name) 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 - // #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) fNext(NULL)
{ {
@@ -262,6 +341,8 @@ Inode::Inode(Volume *volume, Inode *parent, const char *name, int32 type)
fID = volume->GetNextNodeID(); fID = volume->GetNextNodeID();
fType = type; fType = type;
fStartFrame = start;
fFrameCount = frames;
fUserID = geteuid(); fUserID = geteuid();
fGroupID = parent ? parent->GroupID() : getegid(); fGroupID = parent ? parent->GroupID() : getegid();
@@ -289,7 +370,16 @@ Inode::InitCheck()
status_t status_t
Inode::SetName(const char* name) 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) || strchr(newName, '/') != NULL)
return B_BAD_VALUE; 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 ; 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 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 fs_shell ;
#SubInclude HAIKU_TOP src tests add-ons kernel file_systems iso9660 ; #SubInclude HAIKU_TOP src tests add-ons kernel file_systems iso9660 ;
SubInclude HAIKU_TOP src tests add-ons kernel file_systems udf ; SubInclude HAIKU_TOP src tests add-ons kernel file_systems udf ;
@@ -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
;
@@ -0,0 +1,48 @@
/*
* Copyright 2007, Axel Dörfler, [email protected].
* 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);
}