|
From: Ben O. <ben...@us...> - 2003-08-03 23:14:12
|
Update of /cvsroot/njbfs/njbfs
In directory sc8-pr-cvs1:/tmp/cvs-serv4454
Added Files:
Tag: ben
njbfs_id3.c njbfs_id3.h
Log Message:
Ben: get it compilable again
--- NEW FILE: njbfs_id3.c ---
/*
* Nomad Jukebox filesystem for Linux.
*
* Copyright (C) 2001 Jörg Prante <joe...@gm...>
* Copyright (C) 2002 Ben Osheroff <be...@gi...>
*
* based on ftpfs by Florin Malita <fm...@ya...>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/usb.h>
#include "njbfs.h"
#include "njbfs_id3.h"
#include "proc.h"
#include "mpg123/id3.h"
int write_id3v2_frame(char *buf, char *id, char *val, off_t left)
{
u_int32_t size;
int i, count = 0;
if ( left < 11 )
return -ENOMEM;
for (i = 0; i < 4; i++, count++) {
buf[count] = id[i];
}
size = __cpu_to_be32((u_int32_t) strlen(val) + 1);
memcpy((void *) buf + count, &size, 4);
count += 4;
/* defaults for frame header tag, zero */
buf[count++] = 0x0;
buf[count++] = 0x0;
/* this signifies iso-whatever (standard) encoding */
buf[count++] = 0x0;
for (i = 0; val[i]; i++) {
if ( left - count <= 0 )
return -ENOMEM;
buf[count++] = val[i];
}
return count;
}
int write_id3v2_frame_numeric(char *buf, char *id, u_int32_t val, off_t left)
{
static char vbuf[80];
sprintf(vbuf, "%u", val);
return write_id3v2_frame(buf, id, vbuf, left);
}
#define WRITE_ID3_FRAME(buf, title, val, bufleft) \
if ( val ) { \
int status = write_id3v2_frame(buf, title, val, bufleft); \
if ( status > 0 ) { \
buf += status; bufleft -=status; \
} else \
return status; \
}
#define WRITE_ID3_FRAME_NUMERIC(buf, title, val, bufleft) \
if ( val ) { \
int status = write_id3v2_frame_numeric(buf, title, val, bufleft); \
if ( status > 0 ) { \
buf += status; bufleft -= status; \
} else \
return status; \
}
/*
* create a "fake" id3v2 tag based on the file given.
* TODO: bounds checking on the buffer
*/
int create_id3v2_tag(struct njbfs_fattr *fattr, char *buffer, off_t bufsize)
{
off_t bufleft;
u_int32_t size;
int i;
char *p;
if ( bufsize < 10 )
return -ENOMEM;
memset(buffer, 0, bufsize);
strcat(buffer, "ID3");
/* set to version 2.3.0 */
buffer[3] = 0x03;
buffer[4] = 0x00;
/* all id3 flags empty */
buffer[5] = 0x00;
/*
* for now, leave bytes 6-9 empty: these are the size
* bytes, and we'll know about the size later
*/
p = buffer + 10;
bufleft = bufsize - 10;
WRITE_ID3_FRAME(p, "TPE1", fattr->artist, bufleft);
WRITE_ID3_FRAME(p, "TIT2", fattr->title, bufleft);
WRITE_ID3_FRAME(p, "TALB", fattr->album, bufleft);
WRITE_ID3_FRAME(p, "TCON", fattr->genre, bufleft);
WRITE_ID3_FRAME_NUMERIC(p, "TRCK", fattr->tracknum, bufleft);
WRITE_ID3_FRAME_NUMERIC(p, "TYER", fattr->year, bufleft);
WRITE_ID3_FRAME_NUMERIC(p, "TLEN", fattr->length * 1000, bufleft);
/* add 100 bytes of padding for future tags */
size = ((p - buffer) - 10) + 100;
/* id3 uses a 28 bit number for tag size. how odd. */
for (i = 0; i <= 4; i++) {
buffer[9 - i] = (char) size & 0x7F;
size >>= 7;
}
return 0;
}
int create_id3v1_tag(struct njbfs_fattr *fattr, char *buffer, off_t bufsize)
{
struct id3v1tag_t tag;
/*
* pointer to location in buffer where we want to create the tag
*/
char *p = (buffer + bufsize) - 128;
memset(buffer, 0, bufsize);
memset(&tag, 0, sizeof(struct id3v1tag_t));
strcpy(tag.tag, "TAG");
if ( fattr->artist )
strncpy(tag.artist, fattr->artist, 30);
if ( fattr->title )
strncpy(tag.title, fattr->title, 30);
if ( fattr->album )
strncpy(tag.album, fattr->album, 30);
if ( fattr->year )
memcpy(tag.year, &fattr->year, 4);
if ( fattr->tracknum )
memcpy(&tag.track_number, &fattr->tracknum, 1);
memcpy(p, &tag, sizeof(struct id3v1tag_t));
return 0;
}
int njbfs_id3frame_to_fattr(id3_frame_t *frame, struct njbfs_fattr *fattr)
{
char *str = NULL;
if ( id3_frame_is_text(frame) )
SAFE_STRDUP(str, frame->fr_data + 1);
switch(frame->fr_desc->fd_id) {
case ID3_TPE1:
fattr->artist = str;
break;
case ID3_TRCK:
fattr->tracknum = simple_strtol(str, NULL, 0);
kfree(str);
break;
case ID3_TALB:
fattr->album = str;
break;
case ID3_TIT2:
fattr->title = str;
break;
case ID3_TCON:
fattr->genre = str;
break;
case ID3_TLEN: /* length in milliseconds, convert to
length in seconds */
fattr->length = simple_strtol(str, NULL, 0) / 1000;
kfree(str);
break;
}
return 0;
}
int read_from_block_cache(struct njbfs_fattr *f, off_t start, off_t needed, void *buf)
{
struct njbfs_block *block;
off_t blocksize, copy, pos = start;
while(pos - start < needed ) {
block = find_in_block_cache(f->bl_wcache, pos);
if ( !block ) /* not enough data, or
non-contiguous data. */
return 0;
blocksize = block->size;
if ( (pos - start) + blocksize > needed ) {
copy = needed - ( pos - start);
} else
copy = blocksize;
memcpy(buf + pos, block->buffer, copy);
pos += copy;
}
return 1;
}
/*
* Reads in an ID3v2 tag from the fattr's block cache
*/
void * read_id3v2_tag(struct njbfs_fattr *f, off_t *size)
{
int i;
void *tagdata;
static char hdrbuf[10];
uint32_t tagsize = 0;
/* grab the ID3 header (10 bytes) */
if (!read_from_block_cache(f, 0, 10, hdrbuf))
return NULL;
if ( strncmp(hdrbuf, "ID3", 3) != 0 )
return NULL;
/* get the size out of the tag. */
for(i=6; i < 10; i++)
tagsize = ((tagsize << 7) | (hdrbuf[i] & ((1 << 7) - 1)));
dbg("id3: tagsize reports as %u", tagsize);
tagsize += 10;
tagdata = kmalloc(tagsize, GFP_KERNEL);
if (!tagdata) {
err("kmalloc error");
return NULL;
}
if ( !read_from_block_cache(f, 0, tagsize, tagdata) ) {
err("incomplete id3 tag written");
return NULL;
}
*size = tagsize;
return tagdata;
}
off_t njbfs_process_id3v2_tag(struct njbfs_fattr *f, void *id3data)
{
struct list_head *list;
id3_t *id3tag;
id3_frame_t *id3frame;
dbg("passing it into open_mem");
/* pass the coagulated buffer into the id3 parser */
id3tag = id3_open_mem(id3data, 0);
kfree(id3data);
if ( !id3tag )
return 0;
/* loop through the frames in the tag, and add them to
our fattr structure */
list_for_each(list, &id3tag->id3_frame) {
id3frame = list_entry(list, id3_frame_t, fr_list);
njbfs_id3frame_to_fattr(id3frame, f);
}
id3_close(id3tag);
return 1;
}
/*
gets an id3 tag from the block_cache
of the specified fattr, and sets fattr->artist,
fattr->album, etc. accordingly. This is the
glue code into the code in /mpg123.
TODO:
add id3v1 parsing
BUGS:
Software *might* re-write just
part of the id3 header (4096-8192) and we'd be
screwed. Although this seems unlikely.
returns 0 if no valid id3 tag was found, or
the size of the id3 tag if found.
*/
off_t njbfs_parse_id3(struct njbfs_fattr *f)
{
off_t size;
void *id3data;
int status;
id3data = read_id3v2_tag(f, &size);
if ( !id3data )
return 0;
else {
status = njbfs_process_id3v2_tag(f, id3data);
if ( status )
return size;
else
return 0;
}
}
--- NEW FILE: njbfs_id3.h ---
#ifndef _NJBFS_ID3_H
#define _NJBFS_ID3_H
struct id3v1tag_t {
char tag[3]; /* always "TAG": defines ID3v1 tag 128 bytes before EOF */
char title[30];
char artist[30];
char album[30];
char year[4];
char comment[28];
char __zero;
unsigned char track_number;
unsigned char genre;
};
off_t njbfs_parse_id3(struct njbfs_fattr *);
int create_id3v1_tag(struct njbfs_fattr *, char *, off_t );
int create_id3v2_tag(struct njbfs_fattr *, char *, off_t );
#endif;
|