From 4412ca091e6379def8bc836163c6b580df76619c Mon Sep 17 00:00:00 2001 From: crunchy Date: Wed, 23 Apr 2003 08:34:01 +0000 Subject: start restructuring --- libmpio/Makefile.am | 47 +- libmpio/cis.c | 81 --- libmpio/cis.h | 42 -- libmpio/defs.h | 334 ----------- libmpio/directory.c | 1318 -------------------------------------------- libmpio/directory.h | 84 --- libmpio/ecc.c | 247 --------- libmpio/ecc.h | 44 -- libmpio/fat.c | 1039 ---------------------------------- libmpio/fat.h | 87 --- libmpio/id3.c | 292 ---------- libmpio/id3.h | 44 -- libmpio/io.c | 1213 ---------------------------------------- libmpio/io.h | 95 ---- libmpio/mpio.c | 1301 ------------------------------------------- libmpio/mpio.h | 218 -------- libmpio/mplib/mplib.c | 1011 +++++++++++++++++++++++++++++++++ libmpio/mplib/mplib.h | 438 +++++++++++++++ libmpio/mplib/mplib_paas.c | 256 +++++++++ libmpio/mplib/mplib_s.c | 1177 +++++++++++++++++++++++++++++++++++++++ libmpio/mplib/mplib_s.h | 153 +++++ libmpio/mplib/xmalloc.c | 167 ++++++ libmpio/mplib/xmalloc.h | 58 ++ libmpio/smartmedia.c | 153 ----- libmpio/smartmedia.h | 47 -- libmpio/src/cis.c | 81 +++ libmpio/src/cis.h | 42 ++ libmpio/src/debug.c | 313 +++++++++++ libmpio/src/debug.h | 110 ++++ libmpio/src/defs.h | 334 +++++++++++ libmpio/src/directory.c | 1318 ++++++++++++++++++++++++++++++++++++++++++++ libmpio/src/directory.h | 84 +++ libmpio/src/ecc.c | 247 +++++++++ libmpio/src/ecc.h | 44 ++ libmpio/src/fat.c | 1039 ++++++++++++++++++++++++++++++++++ libmpio/src/fat.h | 87 +++ libmpio/src/id3.c | 292 ++++++++++ libmpio/src/id3.h | 44 ++ libmpio/src/io.c | 1213 ++++++++++++++++++++++++++++++++++++++++ libmpio/src/io.h | 95 ++++ libmpio/src/mpio.c | 1301 +++++++++++++++++++++++++++++++++++++++++++ libmpio/src/mpio.h | 218 ++++++++ libmpio/src/smartmedia.c | 153 +++++ libmpio/src/smartmedia.h | 47 ++ 44 files changed, 10349 insertions(+), 6659 deletions(-) delete mode 100644 libmpio/cis.c delete mode 100644 libmpio/cis.h delete mode 100644 libmpio/defs.h delete mode 100644 libmpio/directory.c delete mode 100644 libmpio/directory.h delete mode 100644 libmpio/ecc.c delete mode 100644 libmpio/ecc.h delete mode 100644 libmpio/fat.c delete mode 100644 libmpio/fat.h delete mode 100644 libmpio/id3.c delete mode 100644 libmpio/id3.h delete mode 100644 libmpio/io.c delete mode 100644 libmpio/io.h delete mode 100644 libmpio/mpio.c delete mode 100644 libmpio/mpio.h create mode 100644 libmpio/mplib/mplib.c create mode 100644 libmpio/mplib/mplib.h create mode 100644 libmpio/mplib/mplib_paas.c create mode 100644 libmpio/mplib/mplib_s.c create mode 100644 libmpio/mplib/mplib_s.h create mode 100644 libmpio/mplib/xmalloc.c create mode 100644 libmpio/mplib/xmalloc.h delete mode 100644 libmpio/smartmedia.c delete mode 100644 libmpio/smartmedia.h create mode 100644 libmpio/src/cis.c create mode 100644 libmpio/src/cis.h create mode 100644 libmpio/src/debug.c create mode 100644 libmpio/src/debug.h create mode 100644 libmpio/src/defs.h create mode 100644 libmpio/src/directory.c create mode 100644 libmpio/src/directory.h create mode 100644 libmpio/src/ecc.c create mode 100644 libmpio/src/ecc.h create mode 100644 libmpio/src/fat.c create mode 100644 libmpio/src/fat.h create mode 100644 libmpio/src/id3.c create mode 100644 libmpio/src/id3.h create mode 100644 libmpio/src/io.c create mode 100644 libmpio/src/io.h create mode 100644 libmpio/src/mpio.c create mode 100644 libmpio/src/mpio.h create mode 100644 libmpio/src/smartmedia.c create mode 100644 libmpio/src/smartmedia.h (limited to 'libmpio') diff --git a/libmpio/Makefile.am b/libmpio/Makefile.am index 7065833..1451b75 100644 --- a/libmpio/Makefile.am +++ b/libmpio/Makefile.am @@ -2,29 +2,36 @@ INCLUDES=@MPLIB_INCLUDE@ AM_CFLAGS=@MPLIB_CFLAGS@ lib_LTLIBRARIES=libmpio.la -libmpio_la_LIBADD=@MPLIB_LIBADD@ libmpio_la_SOURCES= \ - mpio.c \ - io.c \ - debug.c \ - smartmedia.c \ - directory.c \ - fat.c \ - ecc.c \ - cis.c \ - id3.c + src/mpio.c \ + src/io.c \ + src/debug.c \ + src/smartmedia.c \ + src/directory.c \ + src/fat.c \ + src/ecc.c \ + src/cis.c \ + src/id3.c \ + mplib/mplib.c \ + mplib/mplib_paas.c \ + mplib/mplib_s.c \ + mplib/xmalloc.c pkginclude_HEADERS= \ - mpio.h \ - defs.h + src/mpio.h \ + src/defs.h noinst_HEADERS= \ - io.h \ - debug.h \ - smartmedia.h \ - directory.h \ - fat.h \ - ecc.h \ - cis.h \ - id3.h + src/io.h \ + src/debug.h \ + src/smartmedia.h \ + src/directory.h \ + src/fat.h \ + src/ecc.h \ + src/cis.h \ + src/id3.h \ + mplib/mplib.h \ + mplib/mplib_s.h \ + mplib/xmalloc.h + diff --git a/libmpio/cis.c b/libmpio/cis.c deleted file mode 100644 index c30085b..0000000 --- a/libmpio/cis.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * - * $Id: cis.c,v 1.1 2002/10/06 21:19:50 germeier Exp $ - * - * Library for USB MPIO-* - * - * Markus Germeier (mager@tzi.de) - * - * - * 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 "cis.h" - -/* This data is CIS block (Card Information System) of the SmartMedia - * cards, it can be found here: - * http://www.samsungelectronics.com/semiconductors/flash/technical_data/application_notes/SM_format.pdf (page 8 + 9) - * or on any Smartmedia card - * - * It is not believed to be some kind of trade secret or such, so ... - * ... if we are mistaken, please tell us so. - */ - -char cis_templ[0x80] = { - 0x01, 0x03, 0xd9, 0x01, 0xff, 0x18, 0x02, 0xdf, /* 0x00 */ - 0x01, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x21, - - 0x02, 0x04, 0x01, 0x22, 0x02, 0x01, 0x01, 0x22, /* 0x10 */ - 0x03, 0x02, 0x04, 0x07, 0x1a, 0x05, 0x01, 0x03, - - 0x00, 0x02, 0x0f, 0x1b, 0x08, 0xc0, 0xc0, 0xa1, /* 0x20 */ - 0x01, 0x55, 0x08, 0x00, 0x20, 0x1b, 0x0a, 0xc1, - - 0x41, 0x99, 0x01, 0x55, 0x64, 0xf0, 0xff, 0xff, /* 0x30 */ - 0x20, 0x1b, 0x0c, 0x82, 0x41, 0x18, 0xea, 0x61, - - 0xf0, 0x01, 0x07, 0xf6, 0x03, 0x01, 0xee, 0x1b, /* 0x40 */ - 0x0c, 0x83, 0x41, 0x18, 0xea, 0x61, 0x70, 0x01, - - 0x07, 0x76, 0x03, 0x01, 0xee, 0x15, 0x14, 0x05, /* 0x50 */ - 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - - 0x00, 0x20, 0x20, 0x20, 0x20, 0x00, 0x30, 0x2e, /* 0x60 */ - 0x30, 0x00, 0xff, 0x14, 0x00, 0xff, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - -}; - -BYTE * -mpio_cis_gen() -{ - BYTE *p; - - p = (BYTE *)malloc(SECTOR_SIZE); - - memset(p, 0, SECTOR_SIZE); - memcpy(p, cis_templ, 0x80); - memcpy(p+0x100, cis_templ, 0x80); - - return p; - -} - - - - diff --git a/libmpio/cis.h b/libmpio/cis.h deleted file mode 100644 index c5d83b4..0000000 --- a/libmpio/cis.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * - * $Id: cis.h,v 1.2 2002/10/26 13:07:42 germeier Exp $ - * - * Library for USB MPIO-* - * - * Markus Germeier (mager@tzi.de) - * - * - * 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. - * - * */ - -#ifndef _MPIO_CIS_H_ -#define _MPIO_CIS_H_ - -#include "defs.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* generate and return a fresh CIS block */ -BYTE *mpio_cis_gen(); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/libmpio/defs.h b/libmpio/defs.h deleted file mode 100644 index 44b14e7..0000000 --- a/libmpio/defs.h +++ /dev/null @@ -1,334 +0,0 @@ -/* -*- linux-c -*- */ - -/* - * $Id: defs.h,v 1.22 2003/04/19 09:32:48 germeier Exp $ - * - * Library for USB MPIO-* - * - * Markus Germeier (mager@tzi.de) - * - * uses code from mpio_stat.c by - * Yuji Touya (salmoon@users.sourceforge.net) - * - * - * 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. - * - * */ - -#ifndef _MPIO_DEFS_H_ -#define _MPIO_DEFS_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -typedef unsigned char BYTE; -typedef unsigned short WORD; -typedef unsigned int DWORD; - -/* Memory selection */ -typedef enum { MPIO_INTERNAL_MEM = 0x01, - MPIO_EXTERNAL_MEM = 0x10 } mpio_mem_t; - -/* model type */ -typedef enum { MPIO_MODEL_DME = 0x00, - MPIO_MODEL_DMG = 0x01, - MPIO_MODEL_DMG_PLUS = 0x02, - MPIO_MODEL_DMB = 0x03, - MPIO_MODEL_DMB_PLUS = 0x04, - MPIO_MODEL_DMK = 0x05, - MPIO_MODEL_FD100 = 0x06, - MPIO_MODEL_FL100 = 0x07, - MPIO_MODEL_FY100 = 0x08, - MPIO_MODEL_UNKNOWN = 0x09 } mpio_model_t; - -/* USB commands */ -typedef enum { GET_VERSION = 0x01, - GET_BLOCK = 0x02, - PUT_SECTOR = 0x03, - DEL_BLOCK = 0x04, - GET_SECTOR = 0x06, - GET_SPARE_AREA = 0x07, - PUT_BLOCK = 0x08, - MODIFY_FIRMWARE = 0xa0 } mpio_cmd_t; - -/* file types on internal memory */ -/* found in the code of salmoon, are these needed? -mager */ -typedef enum { FTYPE_CHAN = 0x00, - FTYPE_MUSIC = 0x01, - FTYPE_CONF = 'C', - FTYPE_FONT = 'F', - FTYPE_OTHER = 'H', - FTYPE_MEMO = 'M', - FTYPE_WAV = 'V', - FTYPE_ENTRY = 'R', - FTYPE_DIR = 'D', - FTYPE_PLAIN = '-'} mpio_filetype_t; - -/* fixed filenames */ -#define MPIO_CONFIG_FILE "CONFIG.DAT" -#define MPIO_CHANNEL_FILE "FMCONFIG.DAT" -#define MPIO_MPIO_RECORD "MPIO RECORD" - -/* type of callback functions */ -typedef BYTE (*mpio_callback_t)(int, int) ; -typedef BYTE (*mpio_callback_init_t)(mpio_mem_t, int, int) ; - -/* zone lookup table */ -#define MPIO_ZONE_MAX 8 /* 8* 16MB = 128MB */ -#define MPIO_ZONE_PBLOCKS 1024 /* physical blocks per zone */ -#define MPIO_ZONE_LBLOCKS 1000 /* logical blocks per zone */ -typedef DWORD mpio_zonetable_t[MPIO_ZONE_MAX][MPIO_ZONE_PBLOCKS]; - -#define MPIO_BLOCK_FREE 0xffff -#define MPIO_BLOCK_DEFECT 0xffee -#define MPIO_BLOCK_CIS 0xaaaa -#define MPIO_BLOCK_NOT_FOUND 0xcccccccc - -/* filenames */ -#define MPIO_FILENAME_LEN 129 -typedef BYTE mpio_filename_t[MPIO_FILENAME_LEN]; - -#ifndef NULL -#define NULL 0 -#endif - -#define MPIO_DEVICE "/dev/usb/mpio" -#define MPIO_CHARSET "ISO-8859-15" - -#define MPIO_ID3_FORMAT "%p - %t" - -#define SECTOR_SIZE 0x200 -#define SECTOR_ECC 0x040 -#define SECTOR_TRANS (SECTOR_SIZE + SECTOR_ECC) - -#define BLOCK_SECTORS 0x20 /* 0x10 8MB Smartmedia :salmoon */ -#define BLOCK_SIZE (SECTOR_SIZE * BLOCK_SECTORS) -#define BLOCK_TRANS (BLOCK_SIZE + (SECTOR_ECC * BLOCK_SECTORS)) - -#define DIR_NUM 0x10 -#define DIR_SIZE (SECTOR_SIZE*DIR_NUM) -#define DIR_ENTRY_SIZE 0x20 - -#define SMALL_MEM 0x02 - -#define CMD_SIZE 0x40 - -#define INFO_LINE 129 - -/* error codes */ -typedef struct { - int id; - char *msg; -} mpio_error_t; - -#define MPIO_OK 0 -#define MPIO_ERR_FILE_NOT_FOUND -1 -#define MPIO_ERR_NOT_ENOUGH_SPACE -2 -#define MPIO_ERR_FILE_EXISTS -3 -#define MPIO_ERR_FAT_ERROR -4 -#define MPIO_ERR_READING_FILE -5 -#define MPIO_ERR_PERMISSION_DENIED -6 -#define MPIO_ERR_WRITING_FILE -7 -#define MPIO_ERR_DIR_TOO_LONG -8 -#define MPIO_ERR_DIR_NOT_FOUND -9 -#define MPIO_ERR_DIR_NOT_A_DIR -10 -#define MPIO_ERR_DIR_NAME_ERROR -11 -#define MPIO_ERR_DIR_NOT_EMPTY -12 -#define MPIO_ERR_DEVICE_NOT_READY -13 -#define MPIO_ERR_OUT_OF_MEMORY -14 -#define MPIO_ERR_INTERNAL -15 -/* internal errors, occur when UI has errors! */ -#define MPIO_ERR_INT_STRING_INVALID -101 - -/* get formatted information, about the MPIO player */ - -typedef struct { - BYTE firmware_id[INFO_LINE]; - BYTE firmware_version[INFO_LINE]; - BYTE firmware_date[INFO_LINE]; - - BYTE model[INFO_LINE]; - - BYTE mem_internal[INFO_LINE]; - BYTE mem_external[INFO_LINE]; - -} mpio_info_t; - -/* view of the MPIO firmware */ -typedef struct { - /* everything we get from GET_VERSION */ - BYTE id[12]; - BYTE major[3]; - BYTE minor[3]; - BYTE year[5]; - BYTE month[3]; - BYTE day[3]; -} mpio_firmware_t; - -/* */ -typedef struct { - DWORD NumCylinder; - DWORD NumHead; - DWORD NumSector; - DWORD SumSector; -} mpio_disk_phy_t; - -/* */ - -struct mpio_directory_tx { - BYTE name[INFO_LINE]; - BYTE dir[BLOCK_SIZE]; - - BYTE *dentry; - - struct mpio_directory_tx *prev; - struct mpio_directory_tx *next; - -}; -typedef struct mpio_directory_tx mpio_directory_t; - - -/* view of a SmartMedia(tm) card */ -typedef struct { - BYTE id; - BYTE manufacturer; - WORD size; /* MB */ - BYTE chips; /* this is the hack for - MPIO internal representation, because - there might be up to four chips involved */ - - /* only needed for external SmartMedia cards */ - mpio_disk_phy_t geo; - - BYTE cis[SECTOR_SIZE]; - BYTE mbr[SECTOR_SIZE]; /* Master Boot Record */ - BYTE pbr[SECTOR_SIZE]; /* Partition Boot Record */ - - int pbr_offset; /* sector offset for the PBR */ - int fat_offset; /* sector offset for the FAT */ - int dir_offset; - - /* these are needed for internal and external cards */ - int max_cluster; /* # of clusters actually available */ - int fat_size; /* # sectors for FAT */ - int fat_nums; /* # of FATs */ - BYTE * fat; /* *real FAT (like in block allocation :-) */ - - /* needed for directory support */ - mpio_directory_t *root; /* root directory */ - mpio_directory_t *cdir; /* current directory */ - - /* how many physical blocks are available - * for internal memory is this value equal to max_cluster - */ - int max_blocks; - BYTE * spare; - - /* lookup table for phys.<->log. block mapping */ - mpio_zonetable_t zonetable; - -} mpio_smartmedia_t; - -/* health status of a memory "card" */ -typedef struct { - WORD total; /* total blocks on "card" */ - WORD spare; /* (available spare blocks */ - WORD broken; /* broken blocks */ -} mpio_health_single_t; - -typedef struct { - BYTE num; /* number of chips or zones */ - /* internal: max 4 chips - * external: max 8 zones (128MB) -> max 8 */ - mpio_health_single_t data[8]; -} mpio_health_t; - -/* view of the MPIO-* */ -typedef struct { - BYTE version[CMD_SIZE]; - - int fd; - BYTE *charset; /* charset used for filename conversion */ - - BYTE id3; /* enable/disable ID3 rewriting support */ - BYTE id3_format[INFO_LINE]; - BYTE id3_temp[INFO_LINE]; - - mpio_firmware_t firmware; - - mpio_model_t model; - - mpio_smartmedia_t internal; - mpio_smartmedia_t external; -} mpio_t; - -typedef struct { - mpio_t *m; - BYTE mem; /* internal/external memory */ - - DWORD entry; /* number of FAT entry */ - - /* internal */ - BYTE i_index; /* file index of file to store */ - BYTE i_fat[16]; /* internal FAT entry */ - - /* external */ - DWORD e_sector; /* logical startsector of cluster */ - - /* mapping to HW (== block address) */ - DWORD hw_address; /* 3 bytes block addressing + 1 byte chip */ - -} mpio_fatentry_t; - - -/* these are copied from: - * http://www.linuxhq.com/kernel/v2.4/doc/filesystems/vfat.txt.html - * - */ - -typedef struct { // Short 8.3 names - unsigned char name[8]; // file name - unsigned char ext[3]; // file extension - unsigned char attr; // attribute byte - unsigned char lcase; // Case for base and extension - unsigned char ctime_ms; // Creation time, milliseconds - unsigned char ctime[2]; // Creation time - unsigned char cdate[2]; // Creation date - unsigned char adate[2]; // Last access date - unsigned char reserved[2]; // reserved values (ignored) - unsigned char time[2]; // time stamp - unsigned char date[2]; // date stamp - unsigned char start[2]; // starting cluster number - unsigned char size[4]; // size of the file -} mpio_dir_entry_t; - -typedef struct { // Up to 13 characters of a long name - unsigned char id; // sequence number for slot - unsigned char name0_4[10]; // first 5 characters in name - unsigned char attr; // attribute byte - unsigned char reserved; // always 0 - unsigned char alias_checksum; // checksum for 8.3 alias - unsigned char name5_10[12]; // 6 more characters in name - unsigned char start[2]; // starting cluster number - unsigned char name11_12[4]; // last 2 characters in name -} mpio_dir_slot_t; - -#ifdef __cplusplus -} -#endif - -#endif /* _MPIO_DEFS_H_ */ - diff --git a/libmpio/directory.c b/libmpio/directory.c deleted file mode 100644 index 6f0e82d..0000000 --- a/libmpio/directory.c +++ /dev/null @@ -1,1318 +0,0 @@ -/* - * - * $Id: directory.c,v 1.18 2003/04/19 23:58:02 germeier Exp $ - * - * Library for USB MPIO-* - * - * Markus Germeier (mager@tzi.de) - * - * - * 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 -#include - -#include "debug.h" -#include "io.h" -#include "mpio.h" -#include "directory.h" -#include - -#define UNICODE "UNICODELITTLE" - -/* the following function is copied from the linux kernel v2.4.18 - * file:/usr/src/linux/fs/fat/misc.c - * it was written by Werner Almesberger and Igor Zhbanov - * and is believed to be GPL - */ - -/* Linear day numbers of the respective 1sts in non-leap years. */ - -static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 }; - /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */ - -/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */ - -int date_dos2unix(unsigned short time,unsigned short date) -{ - int month,year,secs; - struct timezone sys_tz; - struct timeval tv; - - gettimeofday(&tv, &sys_tz); - - /* first subtract and mask after that... Otherwise, if - date == 0, bad things happen */ - month = ((date >> 5) - 1) & 15; - year = date >> 9; - secs = (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400* - ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 && - month < 2 ? 1 : 0)+3653); - /* days since 1.1.70 plus 80's leap day */ - secs += sys_tz.tz_minuteswest*60; - return secs; -} - -/* - * charset for filename encoding/converting - */ -BYTE * -mpio_charset_get(mpio_t *m) -{ - return strdup(m->charset); -} - -BYTE -mpio_charset_set(mpio_t *m, BYTE *charset) -{ - iconv_t ic; - int r = 1; - - ic = iconv_open(UNICODE, charset); - if (ic < 0) - r=0; - iconv_close(ic); - - ic = iconv_open(charset, UNICODE); - if (ic < 0) - r=0; - iconv_close(ic); - - if (r) - { - debugn(2, "setting new charset to: \"%s\"\n", charset); - free(m->charset); - m->charset=strdup(charset); - } else { - debugn(2, "could not set charset to: \"%s\"\n", charset); - } - - return r; -} - -int -mpio_directory_init(mpio_t *m, mpio_mem_t mem, mpio_directory_t *dir, - WORD self, WORD parent) -{ - mpio_dir_entry_t *dentry; - - memset(dir->dir, 0, BLOCK_SIZE); - memset(dir->dir, 0x20, 11); - memset(dir->dir+0x20, 0x20, 11); - - dentry = (mpio_dir_entry_t *)dir->dir; - - strncpy(dentry->name, ". ", 8); - strncpy(dentry->ext, " ", 3); - dentry->start[0] = self & 0xff; - dentry->start[1] = self / 0x100; - dentry->attr = 0x10; - - dentry++; - strncpy(dentry->name, ".. ", 8); - strncpy(dentry->ext, " ", 3); - dentry->start[0] = parent & 0xff; - dentry->start[1] = parent / 0x100; - dentry->attr = 0x10; - - hexdumpn(2, dir->dir, 64); - - return 0; -} - - -int -mpio_directory_read(mpio_t *m, mpio_mem_t mem, mpio_directory_t *dir) -{ - mpio_fatentry_t *f = 0; - - f = mpio_dentry_get_startcluster(m, mem, dir->dentry); - - if (!f) - { - debug("something bad has happened here!"); - exit (-1); - } - - mpio_io_block_read(m, mem, f, dir->dir); - - hexdumpn(5, dir->dir, DIR_SIZE); - - return 0; -} - -BYTE -mpio_directory_is_empty(mpio_t *m, mpio_mem_t mem, mpio_directory_t *dir) -{ - mpio_dir_entry_t *dentry; - BYTE r; - - dentry = (mpio_dir_entry_t *)dir->dir; - dentry += 2; - - r = MPIO_OK; - if (dentry->name[0] != 0x00) - r = !r; - - return r; -} - - -int -mpio_directory_write(mpio_t *m, mpio_mem_t mem, mpio_directory_t *dir) -{ - mpio_fatentry_t *f = 0; - - f = mpio_dentry_get_startcluster(m, mem, dir->dentry); - if (!f) - { - debug("something bad has happened here!"); - exit (-1); - } - - if (mem==MPIO_INTERNAL_MEM) - { - f->i_fat[0x01]= f->i_index; - if (m->model >= MPIO_MODEL_FD100) - f->i_fat[0x0e] = f->i_index; - - /* only one block needed for directory */ - f->i_fat[0x02]=0; - f->i_fat[0x03]=1; - - /* set type to directory */ - f->i_fat[0x06] = FTYPE_ENTRY; - - hexdumpn(2, f->i_fat, 16); - } - - mpio_io_block_delete(m, mem, f); - mpio_io_block_write(m, mem, f, dir->dir); - - return 0; -} - -/* directory operations */ -BYTE * -mpio_directory_open(mpio_t *m, mpio_mem_t mem) -{ - BYTE *out; - if (mem == MPIO_EXTERNAL_MEM) { - if (m->external.id) { - out = m->external.cdir->dir; - } else { - return NULL; - } - } else { - out = m->internal.cdir->dir; - } - - if (out[0] == 0x00) - { - debugn(3, "directory is empty\n"); - return NULL; - } - - debugn(3, "first dentry: %08x\n", out); - - return out; -} - -int -mpio_directory_make(mpio_t *m, mpio_mem_t mem, BYTE *dir) -{ - mpio_smartmedia_t *sm; - mpio_directory_t *new; - mpio_fatentry_t *f, *current; - WORD self, parent; - struct tm tt; - time_t curr; - - if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; - if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; - - if ((strcmp(dir, "..") == 0) || - (strcmp(dir, ".") == 0)) - { - debugn(2, "directory name not allowed: %s\n", dir); - return MPIO_ERR_DIR_NAME_ERROR; - } - - /* find free sector */ - f = mpio_fatentry_find_free(m, mem, FTYPE_ENTRY); - if (!f) - { - debug("could not free cluster for file!\n"); - return (MPIO_ERR_FAT_ERROR); - } else { - self=f->entry; - } - - /* find file-id for internal memory */ - if (mem==MPIO_INTERNAL_MEM) - { - f->i_index=mpio_fat_internal_find_fileindex(m); - debugn(2, "fileindex: %02x\n", f->i_index); - f->i_fat[0x01]= f->i_index; - if (m->model >= MPIO_MODEL_FD100) - f->i_fat[0x0e] = f->i_index; - self = f->i_index; - - /* only one block needed for directory */ - f->i_fat[0x02]=0; - f->i_fat[0x03]=1; - hexdumpn(2, f->i_fat, 16); - } - - if (sm->cdir == sm->root) - { - parent=0; - } else { - current = mpio_dentry_get_startcluster(m, mem, sm->cdir->dentry); - if (mem==MPIO_INTERNAL_MEM) - { - parent = current->i_index; - } else { - parent = current->entry; - } - } - - - new = malloc(sizeof(mpio_directory_t)); - mpio_directory_init(m, mem, new, self, parent); - - mpio_fatentry_set_eof(m ,mem, f); - mpio_io_block_write(m, mem, f, new->dir); - time(&curr); - tt = * localtime(&curr); - mpio_dentry_put(m, mem, - dir, strlen(dir), - mktime(&tt), - 0, self, 0x10); - - free(new); - - return MPIO_OK; -} - -int -mpio_directory_cd(mpio_t *m, mpio_mem_t mem, BYTE *dir) -{ - mpio_smartmedia_t *sm; - BYTE *p; - BYTE month, day, hour, minute, type; - BYTE fname[100]; - WORD year; - DWORD fsize; - int i, size; - BYTE pwd[INFO_LINE]; - mpio_directory_t *old, *new; - - if (strcmp(dir, ".")==0) - return MPIO_OK; - - if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; - if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; - - if (strcmp(dir, "..") == 0) - { - if (sm->cdir->prev) - { - old = sm->cdir; - sm->cdir = sm->cdir->prev; - sm->cdir->next = NULL; - free(old); - } - - return MPIO_OK; - } - - mpio_directory_pwd(m, mem, pwd); - - if ((strlen(pwd) + strlen(dir) + 2) > INFO_LINE) - { - debugn(2, "directory name gets to long!\n"); - return MPIO_ERR_DIR_TOO_LONG; - } - - - p = mpio_dentry_find_name(m, mem, dir); - - /* second try */ - if (!p) - p = mpio_dentry_find_name_8_3(m, mem, dir); - - if (!p) - { - debugn(2, "could not find directory: %s\n", dir); - return MPIO_ERR_DIR_NOT_FOUND; - } - - mpio_dentry_get(m, mem, p, - fname, 100, - &year, &month, &day, - &hour, &minute, &fsize, - &type); - - if (type != FTYPE_DIR) - { - debugn(2, "this is not a directory: %s\n", dir); - return MPIO_ERR_DIR_NOT_A_DIR; - } - - new = malloc(sizeof(mpio_directory_t)); - strcpy(new->name, dir); - new->next = NULL; - new->prev = sm->cdir; - new->dentry = p; - sm->cdir->next = new; - sm->cdir = new; - - mpio_directory_pwd(m, mem, pwd); - - if (strcmp(dir, "/") != 0) - { - /* read new directory */ - size=mpio_directory_read(m, mem, sm->cdir); - } - - return MPIO_OK; - -} - - -void -mpio_directory_pwd(mpio_t *m, mpio_mem_t mem, BYTE pwd[INFO_LINE]) -{ - mpio_smartmedia_t *sm; - mpio_directory_t *d; - - if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; - if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; - - d = sm->root->next; - pwd[0] = 0; - - if (!d) - strcat(pwd, "/"); - - while (d) - { - strcat(pwd, "/"); - debugn(2, "name: %s\n", d->name); - strcat(pwd, d->name); - d = d->next; - } - - return; -} - -mpio_dir_entry_t * -mpio_dentry_filename_write(mpio_t *m, mpio_mem_t mem, BYTE *p, - BYTE *filename, int filename_size) -{ - BYTE *unicode = 0; - BYTE *back, *fback; - BYTE *fname = 0; - iconv_t ic; - int in = 0, out = 0; - int fin = 0, fout = 0; - int count = 0; - BYTE index; - BYTE f_8_3[13]; - mpio_dir_slot_t *slot; - mpio_dir_entry_t *dentry; - int i, j, points; - - /* generate vfat filename in UNICODE */ - ic = iconv_open(UNICODE, m->charset); - fin = in = filename_size + 1; - fout = out = filename_size * 2 + 2 + 26; - fname = malloc(in); - fback = fname; - unicode = malloc(out); - back = unicode; - - memset(fname, 0, in); - snprintf(fname, in, "%s", filename); - memset(unicode, 0xff, out); - iconv(ic, (char **)&fback, &fin, (char **)&back, &fout); - iconv_close(ic); - hexdump(fname, in); - hexdump(unicode, out); - - back = unicode; - - count = filename_size / 13; - if (filename_size % 13) - count++; - - slot = (mpio_dir_slot_t *)p; - - index = 0x40 + count; - while (count > 0) { - mpio_dentry_copy_to_slot(back + ((count - 1) * 26), slot); - hexdump((char *)back + ((count - 1) * 26), 0x20); - slot->id = index; - slot->attr = 0x0f; - slot->reserved = 0x00; - slot->start[0] = 0x00; - slot->start[1] = 0x00; - /* FIXME: */ - slot->alias_checksum = 0x00; // checksum for 8.3 alias - - hexdump((char *)slot, 0x20); - - slot++; - count--; - index = count; - } - -/* memcpy(p, m->internal.dir+0x220, 0x20); */ - -/* p+=0x20; */ - dentry = (mpio_dir_entry_t *)slot; - - /* find uniq 8.3 filename */ - memset(f_8_3, 0x20, 12); - f_8_3[8]='.'; - f_8_3[12]=0x00; - - i=0; - points=0; - /* count points to later find the correct file extension */ - while (i<(strlen(filename))) - { - if (filename[i] == '.') - points++; - i++; - } - - /* if we do not find any points we set the value ridiculously high, - then everything falls into place */ - if (!points) - points=1024*1024; - - i=j=0; - while ((j<8) && (points) && (i<(strlen(filename)))) - { - if (filename[i] == '.') - { - points--; - } else { - if (filename[i]!=' ') { - f_8_3[j] = toupper(filename[i]); - j++; - } - } - i++; - } - - j=i; - while((points) && (j<(strlen(filename)))) - { - if (filename[j] == '.') - points--; - j++; - } - - i=9; - while ((i<12) && (j<(strlen(filename)))) - { - f_8_3[i] = toupper(filename[j]); - i++; - j++; - } - - /* This seems like a special case to me! */ - if (strcmp(MPIO_MPIO_RECORD, filename)==0) - { - f_8_3[6]='~'; - f_8_3[7]='0'; - } - - if (mpio_dentry_find_name_8_3(m, mem, f_8_3)) - { - f_8_3[6]='~'; - f_8_3[7]='1'; - } - - while(mpio_dentry_find_name_8_3(m, mem, f_8_3)) - f_8_3[7]++; - - -/* memcpy(dentry->name,"AAAAAAAA",8); */ -/* memcpy(dentry->ext,"MP3",3); */ - -/* hexdumpn(0, f_8_3, 13); */ - - memcpy(dentry->name, f_8_3, 8); - memcpy(dentry->ext, f_8_3+9, 3); - - free(unicode); - free(fname); - - return dentry; -} - - -int -mpio_dentry_get_size(mpio_t *m, mpio_mem_t mem, BYTE *buffer) -{ - mpio_dir_entry_t *dentry; - - if (!buffer) - return -1; - - UNUSED(m); - - dentry = (mpio_dir_entry_t *)buffer; - - if ((dentry->name[0] & 0x40) && - (dentry->attr == 0x0f) && - (dentry->start[0] == 0x00) && - (dentry->start[1] == 0x00)) { - dentry++; - while ((dentry->attr == 0x0f) && - (dentry->start[0] == 0x00) && - (dentry->start[1] == 0x00)) { - /* this/these are vfat slots */ - dentry++; - } - } - dentry++; - - return(((BYTE *)dentry) - buffer); -} - -BYTE* -mpio_dentry_next(mpio_t *m, mpio_mem_t mem, BYTE *buffer) -{ - int size; - BYTE *out; - - size = mpio_dentry_get_size(m, mem, buffer); - - if (size<=0) - return NULL; - - out = buffer + size; - - if (*out == 0x00) - { - debugn(3, "no more entries\n"); - return NULL; - } - - debugn(3, "next dentry: %08x\n", out); - - return out; -} - -int -mpio_dentry_get_raw(mpio_t *m, mpio_mem_t mem, BYTE *dentry, - BYTE *buffer, int bufsize) -{ - int size; - - size = mpio_dentry_get_size(m, mem, buffer); - debugn(3, "dentry size is: 0x%02x\n", size); - - if (size < 0) - return size; - - if (size > bufsize) - return -2; - - memcpy(buffer, dentry, size); - - return size; -} - -void -mpio_dentry_copy_from_slot(BYTE *buffer, mpio_dir_slot_t *slot) -{ - memcpy(buffer, slot->name0_4, 10); - memcpy(buffer + 10, slot->name5_10, 12); - memcpy(buffer + 22, slot->name11_12, 4); -} - -void -mpio_dentry_copy_to_slot(BYTE *buffer, mpio_dir_slot_t *slot) -{ - memcpy(slot->name0_4, buffer, 10); - memcpy(slot->name5_10, buffer + 10, 12); - memcpy(slot->name11_12, buffer + 22, 4); -} - -int -mpio_dentry_get(mpio_t *m, mpio_mem_t mem, BYTE *buffer, - BYTE *filename, int filename_size, - WORD *year, BYTE *month, BYTE *day, - BYTE *hour, BYTE *minute, DWORD *fsize, BYTE *type) -{ - BYTE filename_8_3[13]; - - return mpio_dentry_get_real(m, mem, buffer, filename, filename_size, - filename_8_3, - year, month, day, hour, minute, fsize, type); -} - -/* TODO: please clean me up !!! */ -int -mpio_dentry_get_real(mpio_t *m, mpio_mem_t mem, BYTE *buffer, - BYTE *filename, int filename_size, - BYTE *filename_8_3, - WORD *year, BYTE *month, BYTE *day, - BYTE *hour, BYTE *minute, DWORD *fsize, - BYTE *type) -{ - int date, time; - int vfat = 0; - int num_slots = 0; - int slots = 0; - int in = 0, out = 0, iconv_return; - mpio_dir_entry_t *dentry; - mpio_dir_slot_t *slot; - BYTE *unicode = 0; - BYTE *uc; - BYTE *fname = 0; - iconv_t ic; - int dsize, i; - - if (buffer == NULL) - return -1; - - dentry = (mpio_dir_entry_t *)buffer; - - if ((dentry->name[0] & 0x40) && - (dentry->attr == 0x0f) && - (dentry->start[0] == 0x00) && - (dentry->start[1] == 0x00)) - { - dsize = mpio_dentry_get_size(m, mem, buffer); - debugn(3, "dentry size is: 0x%02x\n", dsize); - hexdump(buffer, dsize); - num_slots = (dsize / 0x20) - 1; - slots = num_slots - 1; - dentry++; - vfat++; - in = num_slots * 26; - out = num_slots * 13; - unicode = malloc(in + 2); - memset(unicode, 0x00, (in+2)); - uc = unicode; - fname = filename; - slot = (mpio_dir_slot_t *)buffer; - mpio_dentry_copy_from_slot(unicode + (26 * slots), slot); - slots--; - - while ((dentry->attr == 0x0f) && - (dentry->start[0] == 0x00) && - (dentry->start[1] == 0x00)) - { - /* this/these are vfat slots */ - slot = (mpio_dir_slot_t *)dentry; - mpio_dentry_copy_from_slot((unicode + (26 * slots)), slot); - dentry++; - slots--; - } - } - - if (vfat) - { - ic = iconv_open(m->charset, UNICODE); - memset(fname, 0, filename_size); - hexdumpn(4, unicode, in+2); - debugn(4, "before iconv: in: %2d - out: %2d\n", in, out); - iconv_return = iconv(ic, (char **)&uc, &in, (char **)&fname, &out); - debugn(4, "after iconv: in: %2d - out: %2d (return: %d)\n", in, out, - iconv_return); - hexdumpn(4, filename, (num_slots*13)-out); - iconv_close(ic); - } - free(unicode); - - memcpy(filename_8_3, dentry->name, 8); - i=8; - while(filename_8_3[i-1]==' ') - i--; - filename_8_3[i++] = '.'; - memcpy(filename_8_3 + i, dentry->ext, 3); - i+=3; - while(filename_8_3[i-1]==' ') - i--; - filename_8_3[i] = 0; - hexdumpn(4, filename_8_3, 13); - - if (!vfat) - { - if (filename_size >= 12) - { - snprintf(filename, 13, "%s", filename_8_3); - /* UGLY !! */ - if (((strncmp(dentry->name, ". ", 8)==0) && - (strncmp(dentry->ext, " ", 3) == 0))) - filename[1]=0; - if (((strncmp(dentry->name, ".. ", 8)==0) && - (strncmp(dentry->ext, " ", 3) == 0))) - filename[2]=0; - } else { - snprintf(filename, filename_size, "%s", "ERROR"); - } - } - - date = (dentry->date[1] * 0x100) + dentry->date[0]; - *year = date / 512 + 1980; - *month = (date / 32) & 0xf; - *day = date & 0x1f; - - time = (dentry->time[1] * 0x100) + dentry->time[0]; - *hour = time / 2048; - *minute= (time / 32) & 0x3f; - - *fsize = dentry->size[3]; - *fsize *= 0x100; - *fsize += dentry->size[2]; - *fsize *= 0x100; - *fsize += dentry->size[1]; - *fsize *= 0x100; - *fsize += dentry->size[0]; - - if (dentry->attr & 0x10) { - /* is this a directory? */ - *type = FTYPE_DIR; - } else { - *type = FTYPE_PLAIN; - } - - return(((BYTE *)dentry) - buffer); -} - -/* read "size" sectors of fat into the provided buffer */ -int -mpio_rootdir_read (mpio_t *m, mpio_mem_t mem) -{ - mpio_smartmedia_t *sm; - BYTE recvbuff[SECTOR_SIZE]; - int i; - - if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; - if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; - - for (i = 0; i < DIR_NUM; i++) { - if (mpio_io_sector_read(m, mem, (sm->dir_offset + i), recvbuff)) - return 1; - - memcpy(sm->root->dir + (i * SECTOR_SIZE), recvbuff, SECTOR_SIZE); - } - - return (0); -} - -int -mpio_rootdir_clear (mpio_t *m, mpio_mem_t mem) -{ - mpio_smartmedia_t *sm; - - if (mem == MPIO_INTERNAL_MEM) sm=&m->internal; - if (mem == MPIO_EXTERNAL_MEM) sm=&m->external; - - memset(sm->root->dir, 0x00, DIR_SIZE); - - return 0; -} - -BYTE -mpio_dentry_is_dir(mpio_t *m, mpio_mem_t mem, BYTE *p) -{ - int s; - mpio_dir_entry_t *dentry; - BYTE r; - - s = mpio_dentry_get_size(m, mem, p); - s -= DIR_ENTRY_SIZE ; - - dentry = (mpio_dir_entry_t *)p; - - while (s != 0) { - dentry++; - s -= DIR_ENTRY_SIZE ; - } - - if (dentry->attr & 0x10) { - r = MPIO_OK; - } else { - r= !MPIO_OK; - } - - return r; -} - -int -mpio_dentry_get_filesize(mpio_t *m, mpio_mem_t mem, BYTE *p) -{ - int s; - int fsize; - mpio_dir_entry_t *dentry; - - s = mpio_dentry_get_size(m, mem, p); - s -= DIR_ENTRY_SIZE ; - - dentry = (mpio_dir_entry_t *)p; - - while (s != 0) { - dentry++; - s -= DIR_ENTRY_SIZE ; - } - - if (dentry->attr & 0x10) { - fsize = BLOCK_SIZE; - } else { - fsize = dentry->size[3]; - fsize *= 0x100; - fsize += dentry->size[2]; - fsize *= 0x100; - fsize += dentry->size[1]; - fsize *= 0x100; - fsize += dentry->size[0]; - } - - return fsize; -} - -long -mpio_dentry_get_time(mpio_t *m, mpio_mem_t mem, BYTE *p) -{ - int s; - mpio_dir_entry_t *dentry; - - s = mpio_dentry_get_size(m, mem, p); - s -= DIR_ENTRY_SIZE ; - - dentry = (mpio_dir_entry_t *)p; - - while (s != 0) { - dentry++; - s -= DIR_ENTRY_SIZE ; - } - - - return date_dos2unix((dentry->time[0]+dentry->time[1]*0x100), - (dentry->date[0]+dentry->date[1]*0x100)); -} - - - -mpio_fatentry_t * -mpio_dentry_get_startcluster(mpio_t *m, mpio_mem_t mem, BYTE *p) -{ - int s; - DWORD cluster; - BYTE i_index; - mpio_dir_slot_t *dentry; - mpio_fatentry_t *new; - - s = mpio_dentry_get_size(m, mem, p); - s -= DIR_ENTRY_SIZE ; - - dentry = (mpio_dir_slot_t *)p; - - while (s != 0) { - dentry++; - s -= DIR_ENTRY_SIZE ; - } - - cluster = dentry->start[1] * 0x100 + dentry->start[0]; - - if (mem == MPIO_INTERNAL_MEM) - { - i_index=dentry->start[0]; - cluster = mpio_fat_internal_find_startsector(m, cluster); - } - if (cluster < 0) - return NULL; - - new = mpio_fatentry_new(m, mem, cluster, FTYPE_MUSIC); - - if (mem == MPIO_INTERNAL_MEM) - { - new->entry=cluster; - new->i_index=i_index; - mpio_fatentry_entry2hw(m, new); - } - - debugn(2,"i_index=0x%02x\n", new->i_index); - - return new; -} - -int -mpio_dentry_put(mpio_t *m, mpio_mem_t mem, - BYTE *filename, int filename_size, - time_t date, DWORD fsize, WORD ssector, BYTE attr) -{ - BYTE *p; - mpio_dir_entry_t *dentry; - - /* read and copied code from mtools-3.9.8/directory.c - * to make this one right - */ - struct tm *now; - time_t date2 = date; - unsigned char hour, min_hi, min_low, sec; - unsigned char year, month_hi, month_low, day; - - - p = mpio_directory_open(m, mem); - if (p) { - while (*p != 0x00) - p += 0x20; - } else { - if (mem == MPIO_EXTERNAL_MEM) - p = m->external.cdir->dir; - if (mem == MPIO_INTERNAL_MEM) - p = m->internal.cdir->dir; - } - - dentry = mpio_dentry_filename_write(m, mem, p, filename, filename_size); - - dentry->attr = attr; - dentry->lcase = 0x00; - - /* read and copied code from mtools-3.9.8/directory.c - * to make this one right - */ - now = localtime(&date2); - dentry->ctime_ms = 0; - hour = now->tm_hour << 3; - min_hi = now->tm_min >> 3; - min_low = now->tm_min << 5; - sec = now->tm_sec / 2; - dentry->ctime[1] = dentry->time[1] = hour + min_hi; - dentry->ctime[0] = dentry->time[0] = min_low + sec; - year = (now->tm_year - 80) << 1; - month_hi = (now->tm_mon + 1) >> 3; - month_low = (now->tm_mon + 1) << 5; - day = now->tm_mday; - dentry -> adate[1] = dentry->cdate[1] = dentry->date[1] = year + month_hi; - dentry -> adate[0] = dentry->cdate[0] = dentry->date[0] = month_low + day; - - dentry->size[0] = fsize & 0xff; - dentry->size[1] = (fsize / 0x100) & 0xff; - dentry->size[2] = (fsize / 0x10000) & 0xff; - dentry->size[3] = (fsize / 0x1000000) & 0xff; - dentry->start[0] = ssector & 0xff; - dentry->start[1] = ssector / 0x100; - - /* what do we want to return? */ - return 0; -} - -BYTE * -mpio_dentry_find_name_8_3(mpio_t *m, BYTE mem, BYTE *filename) -{ - BYTE *p; - BYTE bdummy; - WORD wdummy; - BYTE fname[129]; - BYTE fname_8_3[13]; - DWORD ddummy; - BYTE *found = 0; - int i, j, len; - - p = mpio_directory_open(m, mem); - while ((p) && (!found)) { - mpio_dentry_get_real (m, mem, p, - fname, 128, - fname_8_3, - &wdummy, &bdummy, &bdummy, - &bdummy, &bdummy, &ddummy, &bdummy); - if ((strcmp(fname_8_3, filename) == 0) && - (strcmp(filename,fname_8_3) == 0)) { - found = p; - p = NULL; - } - - p = mpio_dentry_next(m, mem, p); - } - - return found; -} - -BYTE * -mpio_dentry_find_name(mpio_t *m, BYTE mem, BYTE *filename) -{ - BYTE *p; - BYTE bdummy; - WORD wdummy; - BYTE fname[129]; - DWORD ddummy; - BYTE *found = 0; - - p = mpio_directory_open(m, mem); - while ((p) && (!found)) { - mpio_dentry_get (m, mem, p, - fname, 128, - &wdummy, &bdummy, &bdummy, - &bdummy, &bdummy, &ddummy, &bdummy); - if ((strcmp(fname,filename) == 0) && (strcmp(filename,fname) == 0)) { - found = p; - p = NULL; - } - - p = mpio_dentry_next(m, mem, p); - } - - return found; -} - - -int -mpio_dentry_delete(mpio_t *m, BYTE mem, BYTE *filename) -{ - mpio_smartmedia_t *sm; - BYTE *start; - int size; - BYTE tmp[DIR_SIZE]; - - if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; - if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; - - start = mpio_dentry_find_name(m, mem, filename); - - /* second try */ - if (!start) - start = mpio_dentry_find_name_8_3(m, mem, filename); - - if (!start) { - debugn(2, "could not find file: %s\n", filename); - return 0; - } - - size = mpio_dentry_get_size(m, mem, start); - - if (size <= 0) { - debug("fatal error in mpio_dentry_delete\n"); - return 0; - } - - debugn(5, "size: %2x\n", size); - - /* clear new buffer */ - memset(tmp, 0, DIR_SIZE); - /* copy before delete */ - if (start != sm->cdir->dir) - memcpy(tmp, sm->cdir->dir, (start - (sm->cdir->dir))); - /* copy after delete */ - memcpy(tmp + (start - (sm->cdir->dir)), (start + size), - (sm->cdir->dir + DIR_SIZE - (start + size))); - - memcpy(sm->cdir->dir, tmp, DIR_SIZE); - - return 0; -} - -void -mpio_dentry_move(mpio_t *m,mpio_mem_t mem,BYTE *m_file,BYTE *a_file) { - mpio_smartmedia_t *sm; - - BYTE *t0,*t1,*t2,*t3; - - int s0,s1,s2,s3; - int m_file_s,a_file_s; - BYTE tmp[DIR_SIZE]; - BYTE *b_file; - - if (mem == MPIO_INTERNAL_MEM) - sm = &m->internal; - - if (mem == MPIO_EXTERNAL_MEM) - sm = &m->external; - - if (m_file == a_file) - return; - - m_file_s = mpio_dentry_get_size(m, mem, m_file); - a_file_s = mpio_dentry_get_size(m, mem, a_file); - - // -- we determine the 'befor' file. The start of the region which needs to be moved down - // -- if a_file == NULL this is the start of the directory. - - if(a_file==NULL) { - b_file = sm->cdir->dir; - } else { - b_file = a_file + a_file_s; - } - - if(b_file == m_file) { - return; - } - - /** We disect the whole directory in four pieces. - in different ways according to the direction - the directoy entry is moved (up or down). - */ - - if(m_file > b_file) { - fprintf(stderr,"U "); - t0 = sm->cdir->dir; - s0 = b_file - sm->cdir->dir; - - t1 = m_file; - s1 = m_file_s; - - t2 = b_file; - s2 = m_file - b_file; - - t3 = m_file + m_file_s; - s3 = DIR_SIZE - (m_file-sm->cdir->dir) - m_file_s; - } else { - fprintf(stderr,"D "); - t0 = sm->cdir->dir; - s0 = m_file - sm->cdir->dir; - - t1 = m_file + m_file_s; - s1 = a_file + a_file_s - (m_file + m_file_s); - - t2 = m_file; - s2 = m_file_s; - - t3 = b_file; - s3 = DIR_SIZE - (b_file - sm->cdir->dir); - } - - if(s0) { - memcpy(tmp,t0,s0); - } - - if(s1) { - memcpy(tmp + s0 , t1 , s1 ); - } - - if(s2) { - memcpy(tmp + s0 + s1, t2, s2); - } - - if(s3) { - memcpy(tmp + s0 + s1 + s2, t3, s3); - } - - fprintf(stderr," -- t0=%ld, s0=%d, t1=%ld, s1=%d, t2=%ld, s2=%d, t3=%ld, s3=%d; sum=%d, DIRSIZE=%d\n", - (long)t0,s0,(long)t1,s1,(long)t2,s2,(long)t3,s3,s0+s1+s2+s3,DIR_SIZE); - - memcpy(sm->cdir->dir, tmp, DIR_SIZE); -} - -void -mpio_dentry_switch(mpio_t *m, mpio_mem_t mem, BYTE *file1, BYTE *file2) -{ - mpio_smartmedia_t *sm; - BYTE *p1, *p2; - BYTE *current; - int size1 , size2; - BYTE tmp[DIR_SIZE]; - - if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; - if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; - - if (file1 == file2) - return; - - if (file1cdir->dir) - { - memcpy(current, sm->cdir->dir, p1 - sm->cdir->dir); - current += (p1 - sm->cdir->dir); - } - /* the second file*/ - memcpy(current, p2, size2); - current += size2; - /* between the files */ - memcpy(current, p1+size1, (p2-p1-size1)); - current += (p2-p1-size1); - /* the first file */ - memcpy(current, p1, size1); - current += size1; - /* and the rest */ - memcpy(current, p2+size2, (sm->cdir->dir+DIR_SIZE-p2-size2)); - - /* really update the directory */ - memcpy(sm->cdir->dir, tmp, DIR_SIZE); - - return; -} - -void -mpio_dentry_rename(mpio_t *m, mpio_mem_t mem, BYTE *p, BYTE *newfilename) -{ - mpio_smartmedia_t *sm; - BYTE *current; - int size1 , size2, offset, offset_d1, offset_d2; - BYTE tmp[DIR_SIZE]; - - if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; - if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; - - current = sm->cdir->dir; - - size1 = mpio_dentry_get_size(m, mem, p) / 0x20; - size2 = (strlen(newfilename) / 13) + 1; - if ((strlen(newfilename) % 13)) - size2++; - - debugn(2, "size1: %d size2: %d\n", size1, size2); - - /* we want to copy the last dentry to the right location - * so we avoid reading and writing the same information - */ - size1--; /* kludge so we can do compares without worry */ - size2--; - - memcpy(tmp, current, DIR_SIZE); - offset = p - current; - offset_d1 = offset + (size1 * 0x20); - offset_d2 = offset + (size2 * 0x20); - - if (size2>size1) { - /* new filename needs at least one slot more than the old one */ - memcpy(current+offset_d2, tmp+offset_d1, (DIR_SIZE-offset_d1)); - } - - if (size2> offset) & 0x01 ); -} - -int -mpio_ecc_256_gen(BYTE *data, BYTE *ecc) -{ - BYTE p1, p1_; - BYTE p2, p2_; - BYTE p4, p4_; - - BYTE p08, p08_; - BYTE p16, p16_; - BYTE p32, p32_; - BYTE p64, p64_; - - BYTE p0128, p0128_; - BYTE p0256, p0256_; - BYTE p0512, p0512_; - BYTE p1024, p1024_; - - int i, j; - - /* init */ - p1=p1_=0; - p2=p2_=0; - p4=p4_=0; - - p08=p08_=0; - p16=p16_=0; - p32=p32_=0; - p64=p64_=0; - - p0128=p0128_=0; - p0256=p0256_=0; - p0512=p0512_=0; - p1024=p1024_=0; - - /* vertical */ - for (i=0; i<256; i++) { - - /* p1, p1_ */ - p1 ^= (get_bit(data[i], 7) ^ - get_bit(data[i], 5) ^ - get_bit(data[i], 3) ^ - get_bit(data[i], 1)); - p1_^= (get_bit(data[i], 6) ^ - get_bit(data[i], 4) ^ - get_bit(data[i], 2) ^ - get_bit(data[i], 0)); - - /* p2, p2_ */ - p2 ^= (get_bit(data[i], 7) ^ - get_bit(data[i], 6) ^ - get_bit(data[i], 3) ^ - get_bit(data[i], 2)); - p2_^= (get_bit(data[i], 5) ^ - get_bit(data[i], 4) ^ - get_bit(data[i], 1) ^ - get_bit(data[i], 0)); - - /* p4, p4_ */ - p4 ^= (get_bit(data[i], 7) ^ - get_bit(data[i], 6) ^ - get_bit(data[i], 5) ^ - get_bit(data[i], 4)); - p4_^= (get_bit(data[i], 3) ^ - get_bit(data[i], 2) ^ - get_bit(data[i], 1) ^ - get_bit(data[i], 0)); - } - - /* horizontal */ - for (i=0; i<8; i++) { - - for (j=0; j<256; j++) { - - /* p08, p08_ */ - if ((j & 0x01) == 0) - p08_^= get_bit(data[j], i); - if ((j & 0x01) == 1) - p08 ^= get_bit(data[j], i); - - /* p16, p16_ */ - if (((j/2) & 0x01) == 0) - p16_^= get_bit(data[j], i); - if (((j/2) & 0x01) == 1) - p16^= get_bit(data[j], i); - - /* p32, p32_ */ - if (((j/4) & 0x01) == 0) - p32_^= get_bit(data[j], i); - if (((j/4) & 0x01) == 1) - p32^= get_bit(data[j], i); - - /* p64, p64_ */ - if (((j/8) & 0x01) == 0) - p64_^= get_bit(data[j], i); - if (((j/8) & 0x01) == 1) - p64^= get_bit(data[j], i); - - - /* p0128, p0128_ */ - if (((j/16) & 0x01) == 0) - p0128_^= get_bit(data[j], i); - if (((j/16) & 0x01) == 1) - p0128 ^= get_bit(data[j], i); - - /* p0256, p0256_ */ - if (((j/32) & 0x01) == 0) - p0256_^= get_bit(data[j], i); - if (((j/32) & 0x01) == 1) - p0256^= get_bit(data[j], i); - - /* p0512, p0512_ */ - if (((j/64) & 0x01) == 0) - p0512_^= get_bit(data[j], i); - if (((j/64) & 0x01) == 1) - p0512^= get_bit(data[j], i); - - /* p1024, p1024_ */ - if (((j/128) & 0x01) == 0) - p1024_^= get_bit(data[j], i); - if (((j/128) & 0x01) == 1) - p1024^= get_bit(data[j], i); - - } - } - - ecc[0]=~((p64 << 7) | (p64_ << 6) | - (p32 << 5) | (p32_ << 4) | - (p16 << 3) | (p16_ << 2) | - (p08 << 1) | (p08_ << 0)); - - ecc[1]=~((p1024 << 7) | (p1024_ << 6) | - (p0512 << 5) | (p0512_ << 4) | - (p0256 << 3) | (p0256_ << 2) | - (p0128 << 1) | (p0128_ << 0)); - - ecc[2]=~((p4 << 7) | (p4_ << 6) | - (p2 << 5) | (p2_ << 4) | - (p1 << 3) | (p1_ << 2)); - - return 0; -} - - -int -mpio_ecc_256_check(BYTE *data, BYTE *ecc) -{ - BYTE own_ecc[3]; - BYTE check[3]; - BYTE c; - BYTE line, col; - - int v, i; - - mpio_ecc_256_gen(data, own_ecc); - if ((own_ecc[0]^ecc[0])| - (own_ecc[1]^ecc[1])| - (own_ecc[2]^ecc[2])) { - debugn(2, "ECC %2x %2x %2x vs. %2x %2x %2x\n", - ecc[0], ecc[1], ecc[2], own_ecc[0], own_ecc[1], own_ecc[2]); - check[0] = (ecc[0] ^ own_ecc[0]); - check[1] = (ecc[1] ^ own_ecc[1]); - check[2] = (ecc[2] ^ own_ecc[2]); - - v=1; - for(i=0; i<4; i++) - { - if (!((get_bit(check[1], i*2) ^ - (get_bit(check[1], i*2+1))))) - v=0; - if (!((get_bit(check[0], i*2) ^ - (get_bit(check[0], i*2+1))))) - v=0; - } - for(i=1; i<4; i++) - { - if (!((get_bit(check[2], i*2) ^ - (get_bit(check[2], i*2+1))))) - v=0; - } - - if (v) { - debug("correctable error detected ... fixing the bit\n"); - line = get_bit(check[1], 7) * 128 + - get_bit(check[1], 5) * 64 + - get_bit(check[1], 3) * 32 + - get_bit(check[1], 1) * 16 + - get_bit(check[0], 7) * 8 + - get_bit(check[0], 5) * 4 + - get_bit(check[0], 3) * 2 + - get_bit(check[0], 1); - col = get_bit(check[2], 7) * 4 + - get_bit(check[2], 5) * 2 + - get_bit(check[2], 3); - debug ("error in line: %d , col %d\n", line, col); - debug ("defect byte is: %02x\n", data[line]); - data[line] ^= ( 1 << col); - debug ("fixed byte is: %02x\n", data[line]); - } else { - debug("uncorrectable error detected. Sorry you lose!\n"); - return 1; - } - } - - return 0; -} - - - - diff --git a/libmpio/ecc.h b/libmpio/ecc.h deleted file mode 100644 index 6b04191..0000000 --- a/libmpio/ecc.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * - * $Id: ecc.h,v 1.2 2002/10/26 13:07:43 germeier Exp $ - * - * Library for USB MPIO-* - * - * Markus Germeier (mager@tzi.de) - * - * - * 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. - * - * */ - -#ifndef _MPIO_ECC_H_ -#define _MPIO_ECC_H_ - -#include "defs.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* 256 Bytes Data, 3 Byte ECC to generate */ -int mpio_ecc_256_gen(BYTE *, BYTE *); -/* 256 Bytes Data, 3 Bytes ECC to check and possibly correct */ -int mpio_ecc_256_check(BYTE *, BYTE*); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/libmpio/fat.c b/libmpio/fat.c deleted file mode 100644 index f67c2c1..0000000 --- a/libmpio/fat.c +++ /dev/null @@ -1,1039 +0,0 @@ -/* - * - * $Id: fat.c,v 1.27 2003/04/18 13:53:01 germeier Exp $ - * - * Library for USB MPIO-* - * - * Markus Germeier (mager@tzi.de) - * - * - * 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 "fat.h" -#include "io.h" -#include "debug.h" - -#include -#include - -/* I'm lazy so I hard code all the values */ - -BYTE mpio_part_016[0x10] = { - 0x80, 0x02, 0x0a, 0x00, 0x01, 0x03, 0x50, 0xf3, - 0x29, 0x00, 0x00, 0x00, 0xd7, 0x7c, 0x00, 0x00 -}; -BYTE mpio_part_032[0x10] = { - 0x80, 0x02, 0x04, 0x00, 0x01, 0x07, 0x50, 0xf3, - 0x23, 0x00, 0x00, 0x00, 0xdd, 0xf9, 0x00, 0x00 -}; -BYTE mpio_part_064[0x10] = { - 0x80, 0x01, 0x18, 0x00, 0x01, 0x07, 0x60, 0xf3, - 0x37, 0x00, 0x00, 0x00, 0xc9, 0xf3, 0x01, 0x00 -}; -BYTE mpio_part_128[0x10] = { - 0x80, 0x01, 0x10, 0x00, 0x06, 0x0f, 0x60, 0xf3, - 0x2f, 0x00, 0x00, 0x00, 0xd1, 0xe7, 0x03, 0x00 -}; - -/* ------------------------- */ - -BYTE mpio_pbr_head[0x10] = { - 0xe9, 0x00, 0x00, 0x4d, 0x53, 0x44, 0x4f, 0x53, - 0x35, 0x2e, 0x30, 0x00, 0x02, 0x20, 0x01, 0x00 -}; -BYTE mpio_pbr_016[0x13] = { - 0x02, 0x00, 0x01, 0xd7, 0x7c, 0xf8, 0x03, 0x00, - 0x10, 0x00, 0x04, 0x00, 0x29, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00 -}; -BYTE mpio_pbr_032[0x13] = { - 0x02, 0x00, 0x01, 0xdd, 0xf9, 0xf8, 0x06, 0x00, - 0x10, 0x00, 0x08, 0x00, 0x23, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00 -}; -BYTE mpio_pbr_064[0x13] = { - 0x02, 0x00, 0x01, 0x00, 0x00, 0xf8, 0x0c, 0x00, - 0x20, 0x00, 0x08, 0x00, 0x37, 0x00, 0x00, 0x00, - 0xc9, 0xf3, 0x01 -}; -BYTE mpio_pbr_128[0x13] = { - 0x02, 0x00, 0x01, 0x00, 0x00, 0xf8, 0x20, 0x00, - 0x20, 0x00, 0x10, 0x00, 0x2f, 0x00, 0x00, 0x00, - 0xd1, 0xe7, 0x03 -}; - -BYTE * -mpio_mbr_gen(BYTE size) -{ - BYTE *p; - - p = (BYTE *)malloc(SECTOR_SIZE); - memset(p, 0, SECTOR_SIZE); - - /* MBR signature */ - p[0x1fe] = 0x55; - p[0x1ff] = 0xaa; - - /* frist boot partition */ - switch(size) - { - case 16: - memcpy(p+0x1be, mpio_part_016, 0x10); - break; - case 32: - memcpy(p+0x1be, mpio_part_032, 0x10); - break; - case 64: - memcpy(p+0x1be, mpio_part_064, 0x10); - break; - case 128: - memcpy(p+0x1be, mpio_part_128, 0x10); - break; - default: - debug("This should never happen! (%d)\n", size); - exit(-1); - } - - /* all other partitions are set to zero */ - - return p; -} - -BYTE * -mpio_pbr_gen(BYTE size) -{ - BYTE *p; - - p = (BYTE *)malloc(SECTOR_SIZE); - memset(p, 0, SECTOR_SIZE); - - /* MBR signature */ - p[0x1fe] = 0x55; - p[0x1ff] = 0xaa; - - memcpy(p, mpio_pbr_head, 0x10); - /* BIOS parameter etc. */ - switch(size) - { - case 16: - memcpy(p+0x10, mpio_pbr_016, 0x13); - break; - case 32: - memcpy(p+0x10, mpio_pbr_032, 0x13); - break; - case 64: - memcpy(p+0x10, mpio_pbr_064, 0x13); - break; - case 128: - memcpy(p+0x10, mpio_pbr_128, 0x13); - break; - default: - debug("This should never happen! (%d)\n", size); - exit(-1); - } - - /* FAT id */ - if (size >=128) { - strcpy(p+0x36, "FAT16"); - } else { - strcpy(p+0x36, "FAT12"); - } - - return p; -} - -int -mpio_mbr_eval(mpio_smartmedia_t *sm) -{ - BYTE *pe; /* partition entry */ - int sector, head, cylinder; - - if ((sm->mbr[0x1fe] != 0x55) || (sm->mbr[0x1ff] != 0xaa)) - { - debug("This is not the MBR!\n"); - return 1; - } - - /* always use the first partition */ - /* we probably don't need to support others */ - pe = sm->mbr + 0x1be; - - head = (int)(*(pe+0x01) & 0xff); - sector = (int)(*(pe+0x02) & 0x3f); - cylinder = (int)((*(pe+0x02) >> 6) * 0x100 + *(pe + 0x03)); - - sm->pbr_offset=(cylinder * sm->geo.NumHead + head ) * - sm->geo.NumSector + sector - 1; - - return 0; - -} - - -int -mpio_pbr_eval(mpio_smartmedia_t *sm) -{ - BYTE *bpb; /* BIOS Parameter Block */ - int total_sector; - long temp; - - if ((sm->pbr[0x1fe] != 0x55) || (sm->pbr[0x1ff] != 0xaa)) - { - debug("This is not the PBR!\n"); - return 1; - } - - if (strncmp((sm->pbr+0x36),"FAT", 3) != 0) - { - debug("Did not find an FAT signature, *not* good!\n"); - return 2; - } - - bpb = sm->pbr + 0x0b; - - total_sector = (*(sm->pbr+0x14) * 0x100 + *(sm->pbr + 0x13)); - if (!total_sector) - total_sector = (*(sm->pbr+0x23) * 0x1000000 + - *(sm->pbr+0x22) * 0x10000 + - *(sm->pbr+0x21) * 0x100 + - *(sm->pbr+0x20)); - - /* 128 MB need 2 Bytes instead of 1.5 */ - if (sm->size != 128) - { - temp = ((total_sector / 0x20 * 0x03 / 0x02 / 0x200) + 0x01); - } else { - temp = ((total_sector / 0x20 * 0x02 / 0x200) + 0x01); - } - - sm->fat_offset = sm->pbr_offset + 0x01; - sm->fat_size = temp; - sm->fat_nums = *(sm->pbr + 0x10); - sm->dir_offset = sm->pbr_offset + 0x01 + temp * 2; - sm->max_cluster = (total_sector / BLOCK_SECTORS); - /* fix max clusters */ - temp*=2; - while (temp>=0x10) - { - sm->max_cluster--; - temp-=BLOCK_SECTORS; - } - - return 0; -} - - -void -mpio_fatentry_hw2entry(mpio_t *m, mpio_fatentry_t *f) -{ - mpio_smartmedia_t *sm; - BYTE chip, t; - DWORD value; - - if (f->mem == MPIO_INTERNAL_MEM) - { - sm = &m->internal; - - if (f->hw_address == 0xffffffff) - return ; - - value = f->hw_address; - t = value >> 24; - chip = 0; - - while(t/=2) - chip++; - - value &= 0xffffff; - value /= 0x20; - value += chip * (sm->max_cluster / sm->chips); - - f->entry = value; - - return; - } - - debug("This should never happen!\n"); - exit(-1); - - return; -} - - -void -mpio_fatentry_entry2hw(mpio_t *m, mpio_fatentry_t *f) -{ - mpio_smartmedia_t *sm; - DWORD cluster; - BYTE chip; - - if (f->mem == MPIO_INTERNAL_MEM) - { - sm = &m->internal; - - chip = f->entry / (sm->max_cluster / sm->chips); - cluster = f->entry - ((sm->max_cluster / sm->chips) * chip); - cluster *= 0x20; - cluster += 0x01000000 * (1 << chip); - - f->hw_address=cluster; - - return; - } - - debug("This should never happen!\n"); - exit(-1); - - return; -} - - - -int -mpio_bootblocks_read (mpio_t *m, mpio_mem_t mem) -{ - mpio_smartmedia_t *sm=0; - - int error; - - /* this should not be needed for internal memory, but ... */ - if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; - if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; - if (!sm) - return 1; - - /* in case the external mem is defective we need this here! */ - sm->fat=0; - sm->fat_size=0; - sm->fat_nums=0; - - /* TODO: check a few things more, just to be sure */ - - /* read CIS (just in case it might me usefull) */ - if (mpio_io_sector_read(m, mem, MPIO_BLOCK_CIS, sm->cis)) - { - debug("error reading CIS\n"); - return 1; - } - - /* read MBR */ - /* the MBR is always located @ logical block 0, sector 0! */ - if (mpio_io_sector_read(m, mem, 0, sm->mbr)) - { - debug("error reading MBR\n"); - return 1; - } - - if (error=mpio_mbr_eval(sm)) - { - debug("problem with the MBR (#%d), so I won't try to access the card any" - "further.\n", error); - return 1; - } - - /* read PBR */ - if (mpio_io_sector_read(m, mem, sm->pbr_offset, sm->pbr)) - { - debug("error reading PBR\n"); - return 1; - } - - if (error=mpio_pbr_eval(sm)) - { - debug("problem with the PBR (#%d), so I won't try to access the card any" - "further.\n", error); - return 1; - } - - return 0; -} - -mpio_fatentry_t * -mpio_fatentry_new(mpio_t *m, mpio_mem_t mem, DWORD sector, BYTE ftype) -{ - mpio_smartmedia_t *sm; - mpio_fatentry_t *new; - - new = malloc (sizeof(mpio_fatentry_t)); - - if (new) - { - new->m = m; - new->mem = mem; - new->entry = sector; - - /* init FAT entry */ - memset(new->i_fat, 0xff, 0x10); - new->i_fat[0x00] = 0xaa; /* start of file */ - new->i_fat[0x06] = ftype; - new->i_fat[0x0b] = 0x00; - new->i_fat[0x0c] = 0x00; - new->i_fat[0x0d] = 0x00; - if (m->model >= MPIO_MODEL_FD100) { - /* 0x0e is a copy of the file index number */ - new->i_fat[0x0f] = 0x00; - } else { - new->i_fat[0x0e] = 'P'; - new->i_fat[0x0f] = 'C'; - } - } - - if (mem == MPIO_INTERNAL_MEM) - mpio_fatentry_entry2hw(m, new); - - return new; -} - -int -mpio_fatentry_plus_plus(mpio_fatentry_t *f) -{ - f->entry++; - - if (f->mem == MPIO_INTERNAL_MEM) { - if (f->entry >= f->m->internal.max_cluster) - { - f->entry--; - mpio_fatentry_entry2hw(f->m, f); - return 0; - } - mpio_fatentry_entry2hw(f->m, f); - } - - if (f->mem == MPIO_EXTERNAL_MEM) { - if (f->entry > f->m->external.max_cluster) - { - f->entry--; - return 0; - } - } - - return 1; -} - - -/* read "fat_size" sectors of fat into the provided buffer */ -int -mpio_fat_read (mpio_t *m, mpio_mem_t mem, - mpio_callback_init_t progress_callback) -{ - mpio_smartmedia_t *sm; - BYTE recvbuff[SECTOR_SIZE]; - int i; - - if (mem == MPIO_INTERNAL_MEM) - { - sm = &m->internal; - if (mpio_io_spare_read(m, mem, 0, sm->size, 0, sm->fat, - (sm->fat_size * SECTOR_SIZE), progress_callback)) - return 1; - return 0; - } - - if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; - - if (!sm) - return 1; - - for (i = 0; i < sm->fat_size; i++) { - if (mpio_io_sector_read(m, mem, (sm->fat_offset + i), recvbuff)) - return 1; - - memcpy(sm->fat + (i * SECTOR_SIZE), recvbuff, SECTOR_SIZE); - } - - return (0); -} - -int -mpio_fatentry_free(mpio_t *m, mpio_mem_t mem, mpio_fatentry_t *f ) -{ - int e,i ; - mpio_smartmedia_t *sm; - - if (mem == MPIO_INTERNAL_MEM) { - sm = &m->internal; - e = f->entry * 0x10; - - /* be more strict to avoid writing - * to defective blocks! - */ - i=0; - while (i<0x10) - { - if (sm->fat[e+i] != 0xff) - return 0; - i++; - } - return 1; - } - - if (mem == MPIO_EXTERNAL_MEM) { - sm = &m->internal; - if (mpio_fatentry_read(m, mem, f) == 0) - return 1; - } - - return 0; -} - -DWORD -mpio_fatentry_read(mpio_t *m, mpio_mem_t mem, mpio_fatentry_t *f ) -{ - mpio_smartmedia_t *sm; - int e; - int v; - - if (mem == MPIO_INTERNAL_MEM) { - sm = &m->internal; - e = f->entry * 0x10; - if (mpio_fatentry_is_defect(m, mem, f)) - return 0xffffffff; - - /* this is a special system file! */ - if((sm->fat[e+6] != FTYPE_MUSIC) && - (sm->fat[e+7] == 0xff) && - (sm->fat[e+8] == 0x00) && - (sm->fat[e+9] == 0xff) && - (sm->fat[e+10] == 0xff)) - return 0xffffffff; - /* this is a special system file! */ -/* this is not correct!! */ -/* if (sm->fat[e+6] == FTYPE_CONF) */ -/* return 0xffffffff; */ - /* this is a special system file! */ - if((sm->fat[e+6] != FTYPE_MUSIC) && - (sm->fat[e+0x0b] == 0xff) && - (sm->fat[e+0x0c] == 0xff) && - (sm->fat[e+0x0d] == 0xff)) - return 0xffffffff; - - if((sm->fat[e+7] == 0xff) && - (sm->fat[e+8] == 0xff) && - (sm->fat[e+9] == 0xff) && - (sm->fat[e+10] == 0xff)) - return 0xffffffff; - - v = sm->fat[e+7] * 0x1000000 + - sm->fat[e+8] * 0x10000 + - sm->fat[e+9] * 0x100 + - sm->fat[e+10]; - - return v; - } - - if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; - - if (!sm->fat) - { - debug ("error, no space for FAT allocated!\n"); - return 0; - } - - - if (sm->size == 128) { - /* 2 Byte per entry */ - e = f->entry * 2; - v = sm->fat[e + 1] * 0x100 + sm->fat[e]; - } else { - /* 1.5 Byte per entry */ - /* Nibble order: x321 */ - e = (f->entry * 3 / 2); -/* printf("mager: byte (%d/%d)\n", e, e+1); */ - if ((f->entry & 0x01) == 0) { - /* LLxH */ - /* 21x3 */ - v = (sm->fat[e + 1] & 0x0f) * 0x100 + sm->fat[e]; - } else { - /* 1x32 */ - v = (sm->fat[e + 1] * 0x10) + (sm->fat[e] >> 4); - } - } - - return v; -} - -int -mpio_fatentry_write(mpio_t *m, mpio_mem_t mem, mpio_fatentry_t *f, WORD value) -{ - mpio_smartmedia_t *sm; - int e; - BYTE backup; - - if (mem == MPIO_INTERNAL_MEM) - { - debug("This should not be used for internal memory!\n"); - exit(-1); - } - - if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; - - if (sm->size == 128) - { - /* 2 Byte per entry */ - e = f->entry * 2; - sm->fat[e] = value & 0xff; - sm->fat[e + 1] = (value >> 8 ) & 0xff; - } else { - /* 1.5 Byte per entry */ - e = (f->entry * 3 / 2); - if ((f->entry & 0x01) == 0) { - /* 21x3 */ - sm->fat[e] = value & 0xff; - backup = sm->fat[e + 1] & 0xf0; - sm->fat[e + 1] = backup | (( value / 0x100 ) & 0x0f); - } else { - /* 1x32 */ - sm->fat[e + 1] = (value / 0x10) & 0xff; - backup = sm->fat[e] & 0x0f; - sm->fat[e] = backup | ( (value * 0x10) & 0xf0 ); - } - } - - return 0; -} - -int -mpio_fat_internal_find_startsector(mpio_t *m, BYTE start) -{ - mpio_fatentry_t *f; - mpio_smartmedia_t *sm = &m->internal; - int found=-1; - - f = mpio_fatentry_new(m, MPIO_INTERNAL_MEM, 0, FTYPE_MUSIC); - - while(mpio_fatentry_plus_plus(f)) - { - if ((sm->fat[f->entry * 0x10] == 0xaa) && - (sm->fat[f->entry * 0x10 + 1] == start)) - found=f->entry; - } - - free(f); - - return found; -} - -BYTE -mpio_fat_internal_find_fileindex(mpio_t *m) -{ - mpio_fatentry_t *f; - mpio_smartmedia_t *sm = &m->internal; - BYTE index[256]; - BYTE found; /* hmm, ... */ - - memset(index, 1, 256); - - f = mpio_fatentry_new(m, MPIO_INTERNAL_MEM, 0, FTYPE_MUSIC); - while(mpio_fatentry_plus_plus(f)) - { - if (sm->fat[f->entry * 0x10 + 1] != 0xff) - index[sm->fat[f->entry * 0x10 + 1]] = 0; - } - free(f); - - found=6; - while((found<256) && (!index[found])) - found++; - - if (found==256) - { - debug("Oops, did not find a new fileindex!\n" - "This should never happen, aborting now!, Sorry!\n"); - exit(-1); - } - - return found; -} - - -int -mpio_fat_free_clusters(mpio_t *m, mpio_mem_t mem) -{ - mpio_smartmedia_t *sm; - mpio_fatentry_t *f; - int i; - int e = 0; - int fsize; - - if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; - if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; - - if (sm->fat) - { - f = mpio_fatentry_new(m, mem, 0, FTYPE_MUSIC); - do - { - if (mpio_fatentry_free(m, mem, f)) - e++; - } while (mpio_fatentry_plus_plus(f)); - free(f); - } else { - f = 0; - } - - - return (e * 16); -} - -mpio_fatentry_t * -mpio_fatentry_find_free(mpio_t *m, mpio_mem_t mem, BYTE ftype) -{ - mpio_fatentry_t *f; - - f = mpio_fatentry_new(m, mem, 1, ftype); - - while(mpio_fatentry_plus_plus(f)) - { - if (mpio_fatentry_free(m, mem, f)) - return f; - } - - free(f); - - return NULL; -} - -int -mpio_fatentry_next_free(mpio_t *m, mpio_mem_t mem, mpio_fatentry_t *f) -{ - mpio_fatentry_t backup; - - memcpy(&backup, f, sizeof(mpio_fatentry_t)); - - while(mpio_fatentry_plus_plus(f)) - { - if (mpio_fatentry_free(m, mem, f)) - { - if (mem == MPIO_INTERNAL_MEM) - f->i_fat[0x00] = 0xee; - return 1; - } - } - - /* no free entry found, restore entry */ - memcpy(f, &backup, sizeof(mpio_fatentry_t)); - - return 0; -} - -int -mpio_fatentry_next_entry(mpio_t *m, mpio_mem_t mem, mpio_fatentry_t *f) -{ - mpio_smartmedia_t *sm; - DWORD value; - DWORD endvalue; - - value = mpio_fatentry_read(m, mem, f); - - if (value == 0xaaaaaaaa) - return -1; - - if (mem == MPIO_INTERNAL_MEM) - { - sm = &m->internal; - f->hw_address = value; - - mpio_fatentry_hw2entry(m, f); - - endvalue = 0xffffffff; - } - - - if (mem == MPIO_EXTERNAL_MEM) - { - sm = &m->external; - f->entry = value; - - if (sm->size==128) - { - endvalue = 0xfff8; - } else { - endvalue = 0xff8; - } - } - - if (value >= endvalue) - return 0; - - return 1; -} - - -int -mpio_fat_clear(mpio_t *m, mpio_mem_t mem) -{ - mpio_smartmedia_t *sm; - mpio_fatentry_t *f; - - if (mem == MPIO_INTERNAL_MEM) { - sm = &m->internal; - - f = mpio_fatentry_new(m, mem, 1, FTYPE_MUSIC); - do { - mpio_fatentry_set_free(m, mem, f) ; - } while(mpio_fatentry_plus_plus(f)); - free(f); - } - - if (mem == MPIO_EXTERNAL_MEM) { - sm = &m->external; - memset(sm->fat, 0x00, (sm->fat_size * SECTOR_SIZE)); - sm->fat[0] = 0xf8; - sm->fat[1] = 0xff; - sm->fat[2] = 0xff; - /* for FAT 16 */ - if (sm->size == 128) - sm->fat[3] = 0xff; - } - - return 0; -} - -/* - * This function acutally writes both, - * the FAT _and_ the root directory - * - */ - -int -mpio_fat_write(mpio_t *m, mpio_mem_t mem) -{ - mpio_smartmedia_t *sm; - mpio_fatentry_t *f; - BYTE dummy[BLOCK_SIZE]; - WORD i; - DWORD block; - - if (mem == MPIO_INTERNAL_MEM) { - sm = &m->internal; - - if (sm->cdir == sm->root) - { - f=mpio_fatentry_new(m, mem, 0, FTYPE_MUSIC); - mpio_io_block_delete(m, mem, f); - free(f); - - memset(dummy, 0x00, BLOCK_SIZE); - - /* only write the root dir */ - for (i= 0; i< 0x20; i++) - { - - if (iroot->dir + SECTOR_SIZE * i)); - } else { - /* fill the rest of the block with zeros */ - mpio_io_sector_write(m, mem, i, dummy); - } - } - } else { - mpio_directory_write(m, mem, sm->cdir); - } - - } - - if (mem == MPIO_EXTERNAL_MEM) - { - sm=&m->external; - - memset(dummy, 0xff, BLOCK_SIZE); - - for (i = 0; i < (sm->dir_offset + DIR_NUM) ; i++) { - /* before writing to a new block delete it! */ - if (((i / 0x20) * 0x20) == i) { - block = mpio_zone_block_find_seq(m, mem, (i/0x20)); - if (block == MPIO_BLOCK_NOT_FOUND) - { - block = mpio_zone_block_find_free_seq(m, mem, (i/0x20)); - } - if (block == MPIO_BLOCK_NOT_FOUND) - { - debug("This should never happen!"); - exit(-1); - } - - mpio_io_block_delete_phys(m, mem, block); - } - - /* remeber: logical sector 0 is the MBR! */ - if (i == 0) - mpio_io_sector_write(m, mem, 0, sm->mbr); - if ((i > 0) && (i < sm->pbr_offset)) - mpio_io_sector_write(m, mem, i, dummy); - - if (i == sm->pbr_offset) - mpio_io_sector_write(m, mem, sm->pbr_offset, sm->pbr); - - if ((i >= sm->fat_offset) && (i < (sm->fat_offset + (2*sm->fat_size)))) - mpio_io_sector_write(m, mem, i, - (sm->fat + SECTOR_SIZE * - ((i - sm->fat_offset) % sm->fat_size))); - - if (i>=sm->dir_offset) - mpio_io_sector_write(m, mem, i, - (sm->root->dir + - (i - sm->dir_offset) * SECTOR_SIZE)); - } - - if (sm->cdir != sm->root) - mpio_directory_write(m, mem, sm->cdir); - - } - - - return 0; -} - -int -mpio_fatentry_set_free (mpio_t *m, mpio_mem_t mem, mpio_fatentry_t *f) -{ - int e; - mpio_smartmedia_t *sm; - - if (mem == MPIO_INTERNAL_MEM) - { - sm = &m->internal; - e = f->entry * 0x10; - memset((sm->fat+e), 0xff, 0x10); - } - - if (mem == MPIO_EXTERNAL_MEM) - { - sm = &m->internal; - mpio_fatentry_write(m, mem, f, 0); - } - - return 0; -} - -int -mpio_fatentry_set_defect(mpio_t *m, mpio_mem_t mem, mpio_fatentry_t *f) -{ - int e; - mpio_smartmedia_t *sm; - - if (mem == MPIO_INTERNAL_MEM) - { - sm = &m->internal; - e = f->entry * 0x10; - memset((sm->fat+e), 0xaa, 0x10); - } - - if (mem == MPIO_EXTERNAL_MEM) - { - sm = &m->internal; - mpio_fatentry_write(m, mem, f, 0xfff7); - } - - return 0; -} - -int -mpio_fatentry_is_defect(mpio_t *m, mpio_mem_t mem, mpio_fatentry_t *f) -{ - int e; - mpio_smartmedia_t *sm; - - if (mem == MPIO_INTERNAL_MEM) - { - sm = &m->internal; - e = f->entry * 0x10; - if (mpio_fatentry_free(m, mem, f)) - return 0; - /* check if this block became defective */ - if (m->model >= MPIO_MODEL_FD100) { - /* newer models */ - if ((sm->fat[e+0x0f] != 0) || - (sm->fat[e+0x01] != sm->fat[e+0x0e])) - { - debug("defective block encountered, abort reading! (newer models check)\n"); - return 1; - } - } else - if ((sm->fat[e+0x0e] != 'P') || - (sm->fat[e+0x0f] != 'C') || - ((sm->fat[e+0x00] != 0xaa) && - (sm->fat[e+0x00] != 0xee))) - { - debug("defective block encountered, abort reading! (older models check)\n"); - return 1; - } - } - - if (mem == MPIO_EXTERNAL_MEM) - { - if (mpio_fatentry_read(m, mem, f)==0xfff7) - return 1; - } - - return 0; -} - -int -mpio_fatentry_set_eof(mpio_t *m, mpio_mem_t mem, mpio_fatentry_t *f) -{ - int e; - mpio_smartmedia_t *sm; - - if (mem == MPIO_INTERNAL_MEM) - { - sm = &m->internal; - e = f->entry * 0x10; - memset((f->i_fat+0x07), 0xff, 4); - memcpy((sm->fat+e), f->i_fat, 0x10); - } - - if (mem == MPIO_EXTERNAL_MEM) - { - sm = &m->internal; - mpio_fatentry_write(m, mem, f, 0xffff); - } - - return 0; -} - -int -mpio_fatentry_set_next(mpio_t *m, mpio_mem_t mem, - mpio_fatentry_t *f, mpio_fatentry_t *value) -{ - int e; - mpio_smartmedia_t *sm; - - if (mem == MPIO_INTERNAL_MEM) - { - sm = &m->internal; - e = f->entry * 0x10; - - f->i_fat[0x07]= value->hw_address / 0x1000000; - f->i_fat[0x08]=(value->hw_address / 0x10000 ) & 0xff; - f->i_fat[0x09]=(value->hw_address / 0x100 ) & 0xff; - f->i_fat[0x0a]= value->hw_address & 0xff; - - memcpy((sm->fat+e), f->i_fat, 0x10); - } - - if (mem == MPIO_EXTERNAL_MEM) - { - sm = &m->internal; - mpio_fatentry_write(m, mem, f, value->entry); - } - - return 0; -} - diff --git a/libmpio/fat.h b/libmpio/fat.h deleted file mode 100644 index 6b7451f..0000000 --- a/libmpio/fat.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * - * $Id: fat.h,v 1.11 2003/04/18 13:53:01 germeier Exp $ - * - * Library for USB MPIO-* - * - * Markus Germeier (mager@tzi.de) - * - * - * 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. - * - * */ - -#ifndef _MPIO_FAT_H_ -#define _MPIO_FAT_H_ - -#include "defs.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* generate fresh boot sectors for formatting of external mem */ -BYTE *mpio_mbr_gen(BYTE); -BYTE *mpio_pbr_gen(BYTE); - -/* only needed for external memory */ -int mpio_bootblocks_read(mpio_t *, mpio_mem_t); -int mpio_mbr_eval(mpio_smartmedia_t *); -int mpio_pbr_eval(mpio_smartmedia_t *); - -/* functions on the FAT for internal *and* external */ -int mpio_fat_read(mpio_t *, mpio_mem_t, mpio_callback_init_t); -int mpio_fat_write(mpio_t *, mpio_mem_t); -int mpio_fat_clear(mpio_t *, mpio_mem_t); -int mpio_fat_free_clusters(mpio_t *, mpio_mem_t); -int mpio_fat_free(mpio_t *, mpio_mem_t); - -/* functions to iterate through the FAT linked list(s) */ -mpio_fatentry_t *mpio_fatentry_new(mpio_t *, mpio_mem_t, DWORD, BYTE); -int mpio_fatentry_plus_plus(mpio_fatentry_t *); - -mpio_fatentry_t *mpio_fatentry_find_free(mpio_t *, mpio_mem_t, BYTE); -int mpio_fatentry_next_free(mpio_t *, mpio_mem_t, - mpio_fatentry_t *); -int mpio_fatentry_next_entry(mpio_t *, mpio_mem_t, - mpio_fatentry_t *); -DWORD mpio_fatentry_read(mpio_t *, mpio_mem_t, mpio_fatentry_t *); -int mpio_fatentry_write(mpio_t *, mpio_mem_t, mpio_fatentry_t *, - WORD); - -int mpio_fatentry_set_free (mpio_t *, mpio_mem_t, - mpio_fatentry_t *); -int mpio_fatentry_set_defect(mpio_t *, mpio_mem_t, - mpio_fatentry_t *); -int mpio_fatentry_set_eof(mpio_t *, mpio_mem_t, - mpio_fatentry_t *); -int mpio_fatentry_set_next(mpio_t *, mpio_mem_t, - mpio_fatentry_t *, mpio_fatentry_t *); -int mpio_fatentry_is_defect(mpio_t *, mpio_mem_t, - mpio_fatentry_t *); - -/* finding a file is fundamental different for internal mem */ -int mpio_fat_internal_find_startsector(mpio_t *, BYTE); -BYTE mpio_fat_internal_find_fileindex(mpio_t *); - -/* mapping logical <-> physical for internal memory only */ -void mpio_fatentry_hw2entry(mpio_t *, mpio_fatentry_t *); -void mpio_fatentry_entry2hw(mpio_t *, mpio_fatentry_t *); - -#ifdef __cplusplus -} -#endif - -#endif /* _MPIO_FAT_H_ */ diff --git a/libmpio/id3.c b/libmpio/id3.c deleted file mode 100644 index 14e0688..0000000 --- a/libmpio/id3.c +++ /dev/null @@ -1,292 +0,0 @@ -/* - * $Id: id3.c,v 1.2 2003/04/21 10:37:16 germeier Exp $ - * - * Library for accessing Digit@lways MPIO players - * Copyright (C) 2003 Markus Germeier - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc.,g 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include - -#include "id3.h" -#include "debug.h" -#include "mplib.h" - -#ifdef MPLIB -void -mpio_id3_get_content(id3_tag *tag, id3_tag *tag2, int field, - BYTE out[INFO_LINE]) -{ - id3_content *content; - id3_text_content *text_content; - - content = mp_get_content(tag, field); - if (!content) - content = mp_get_content(tag2, field); - if (content) - { - text_content = mp_parse_artist(content); - debugn(2, "Found (%d): %s\n", field, text_content->text); - strncpy(out, text_content->text, INFO_LINE); - } else { - strcpy(out,""); - } - -} - -void -mpio_id3_copy_tag(BYTE *src, BYTE *dest, int *offset) -{ - int i=0; - int last=0; - - /* find last non-space character, so we can strip */ - /* trailing spaces */ - while(src[i]) - if (src[i++]!=0x20) - last=i; - - i=0; - while((*offset<(INFO_LINE-1)) && (src[i]) && (iid3 = value; - return m->id3; -#else - return 0; -#endif /* MPLIB */ -} - -/* query ID3 rewriting support */ -BYTE -mpio_id3_get(mpio_t *m) -{ -#ifdef MPLIB - return m->id3; -#else - return 0; -#endif /* MPLIB */ -} - -/* ID3 rewriting: do the work */ -/* context, src filename, uniq filename template */ -int -mpio_id3_do(mpio_t *m, BYTE *src, BYTE *tmp) -{ -#ifdef MPLIB - int fd, in; - BYTE buf[BLOCK_SIZE]; - int r, w; - int i, j, t; - id3_tag *tag, *tag2, *new_tag; - id3_tag_list *tag_list; - id3_tag_list new_tag_list; - id3_content *content; - id3_content new_content; - id3_text_content *text_content; - id3v2_tag *v2_tag; - BYTE data_artist[INFO_LINE]; - BYTE data_title[INFO_LINE]; - BYTE data_album[INFO_LINE]; - BYTE data_year[INFO_LINE]; - BYTE data_genre[INFO_LINE]; - BYTE data_comment[INFO_LINE]; - BYTE data_track[INFO_LINE]; - - BYTE mpio_tag[INFO_LINE]; - char *mpio_tag_unicode; - - char *uc; - iconv_t ic; - int fin, fout; - char *fback, *back; - - if (!m->id3) - return 0; - - sprintf(tmp, "/tmp/MPIO-XXXXXXXXXXXXXXX", INFO_LINE); - - fd = mkstemp(tmp); - if (fd==-1) return 0; - sprintf(m->id3_temp, tmp, INFO_LINE); - - in = open(src, O_RDONLY); - if (in==-1) return 0; - - do { - r=read(in, buf, BLOCK_SIZE); - if (r>0) - w=write(fd, buf, r); - } while (r>0); - - close (in); - - tag_list = mp_get_tag_list_from_fd(fd); - if (!tag_list) - { - debug("no tag list found!\n"); - return 0; - } - - tag = tag_list->tag; - tag2 = NULL; - if (tag_list->next) - tag2 = tag_list->next->tag; - - /* read tags from file */ - mpio_id3_get_content(tag, tag2, MP_ARTIST, data_artist); - mpio_id3_get_content(tag, tag2, MP_TITLE, data_title); - mpio_id3_get_content(tag, tag2, MP_ALBUM, data_album); - mpio_id3_get_content(tag, tag2, MP_GENRE, data_genre); - mpio_id3_get_content(tag, tag2, MP_COMMENT, data_comment); - mpio_id3_get_content(tag, tag2, MP_YEAR, data_year); - mpio_id3_get_content(tag, tag2, MP_TRACK, data_track); - - /* build new tag */ - mpio_tag[0]=0x00; - i=j=t=0; - - while ((t<(INFO_LINE-1) && m->id3_format[i]!=0)) - { - if (m->id3_format[i] == '%') - { - i++; - switch(m->id3_format[i]) - { - case 'p': - mpio_id3_copy_tag(data_artist, mpio_tag, &t); - break; - case 't': - mpio_id3_copy_tag(data_title, mpio_tag, &t); - break; - case 'a': - mpio_id3_copy_tag(data_album, mpio_tag, &t); - break; - case 'g': - mpio_id3_copy_tag(data_genre, mpio_tag, &t); - break; - case 'c': - mpio_id3_copy_tag(data_comment, mpio_tag, &t); - break; - case 'y': - mpio_id3_copy_tag(data_year, mpio_tag, &t); - break; - case 'n': - mpio_id3_copy_tag(data_track, mpio_tag, &t); - break; - default: - mpio_tag[t] = m->id3_format[i]; - } - } else { - mpio_tag[t] = m->id3_format[i]; - t++; - } - - i++; - } - mpio_tag[t]=0x00; - - debugn(2, "new_tag: %s\n", mpio_tag); - - /* convert tag to UNICODELITTLE */ - fin = strlen(mpio_tag) + 1; - fout = fin*2 + 2; - ic = iconv_open("UNICODELITTLE", "ASCII"); - fback = mpio_tag; - mpio_tag_unicode = (char *)malloc(2*INFO_LINE+3); - back = (char *)mpio_tag_unicode; - *back=0x01; - back++; - *back=0xff; - back++; - *back=0xfe; - back++; - - debugn(2,"iconv before %s %d %d\n", fback, fin, fout); - iconv(ic, (char **)&fback, &fin, (char **)&back, &fout); - debugn(2,"iconv after %s %d %d\n", fback, fin, fout); - iconv_close(ic); - hexdumpn(2, mpio_tag, strlen(mpio_tag)); - hexdumpn(2, (char *)mpio_tag_unicode, (2*strlen(mpio_tag))+3); - - /* build new ID3 v2 tag with only TXXX field */ - new_content.length=(2*strlen(mpio_tag))+3; - new_content.data = (char *)malloc(new_content.length); - new_content.compressed=0; - new_content.encrypted=0; - memcpy(new_content.data, mpio_tag_unicode, new_content.length); - - new_tag = mp_alloc_tag_with_version (2); - mp_set_custom_content(new_tag, "TXXX", &new_content); - - v2_tag = (id3v2_tag *)new_tag->tag; - v2_tag->header->unsyncronization=0; - v2_tag->header->is_experimental=0; - - new_tag_list.tag = new_tag; - new_tag_list.next = NULL; - new_tag_list.first = NULL; - - /* delete ID3 v2 tag from file */ - mp_del_tags_by_ver_from_fd(fd, 2); - close (fd); - - /* write new ID3 v2 tag to file */ - mp_write_to_file(&new_tag_list, tmp); - - free(mpio_tag_unicode); - - return 1; -#else - return 0; -#endif /* MPLIB */ -} - -int -mpio_id3_end(mpio_t *m) -{ -#ifdef MPLIB - if (m->id3_temp[0]) - unlink(m->id3_temp); - m->id3_temp[0] = 0x00; - return 1; -#else - return 0; -#endif /* MPLIB */ -} - -void -mpio_id3_format_set(mpio_t *m, BYTE *format) -{ - strncpy(m->id3_format, format, INFO_LINE); -} - -/* get format string for rewriting*/ -void -mpio_id3_format_get(mpio_t *m, BYTE *format) -{ - strncpy(format, m->id3_format, INFO_LINE); -} diff --git a/libmpio/id3.h b/libmpio/id3.h deleted file mode 100644 index 7ea8940..0000000 --- a/libmpio/id3.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * $Id: id3.h,v 1.1 2003/04/19 09:32:48 germeier Exp $ - * - * Library for accessing Digit@lways MPIO players - * Copyright (C) 2003 Markus Germeier - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#ifndef _MPIO_ID3_H_ -#define _MPIO_ID3_H_ - -#include "defs.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* ID3 rewriting: do the work */ -/* context, src filename, uniq filename template */ -int mpio_id3_do(mpio_t *, BYTE *, BYTE *); - -/* ID3: clean up temp file */ -int mpio_id3_end(mpio_t *); - -#ifdef __cplusplus -} -#endif - - -#endif /* _MPIO_ID3_H_ */ diff --git a/libmpio/io.c b/libmpio/io.c deleted file mode 100644 index 0ef8258..0000000 --- a/libmpio/io.c +++ /dev/null @@ -1,1213 +0,0 @@ -/* -*- linux-c -*- */ - -/* - * - * $Id: io.c,v 1.25 2003/04/18 13:53:01 germeier Exp $ - * - * Library for USB MPIO-* - * - * Markus Germeier (mager@tzi.de) - * - * uses code from mpio_stat.c by - * Yuji Touya (salmoon@users.sourceforge.net) - * - * - * 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. - * - * */ - -/* - * - * low level I/O - * - * - */ - -#include -#include -#include -#include - -#include "io.h" -#include "debug.h" -#include "ecc.h" - -BYTE model2externalmem(mpio_model_t); -DWORD blockaddress_encode(DWORD); -DWORD blockaddress_decode(BYTE *); -void fatentry2hw(mpio_fatentry_t *, BYTE *, DWORD *); - -/* small hack to handle external addressing on different MPIO models */ -BYTE -model2externalmem(mpio_model_t model) -{ - BYTE m; - - switch(model) - { - case MPIO_MODEL_DMG: - case MPIO_MODEL_DMG_PLUS: - m = 0x80; - break; - default: - m = 0x10; - } - - return m; -} - -/* encoding and decoding of blockaddresses */ - -DWORD -blockaddress_encode(DWORD ba) -{ - WORD addr; - BYTE p = 0, c = 0; - BYTE high, low; - - high = 0x10 | ((ba / 0x80) & 0x07); - low = (ba * 2) & 0xff; - - c = high; - while (c) - { - if (c & 0x01) - p ^= 1; - c /= 2; - } - - c = low; - while (c) - { - if (c & 0x01) - p ^= 0x01; - c /= 2; - } - - addr = (high * 0x100) + low + p; - - return addr; -} - - -DWORD -blockaddress_decode(BYTE *entry) -{ - WORD ba; - WORD value; - BYTE p=0, high, low; - int i, t; - - /* check for "easy" defect block */ - t=1; - for(i=0; i<0x10; i++) - if (entry[i] != 0) - t=0; - if (t) - return MPIO_BLOCK_DEFECT; - - /* check for "easy" defect block */ - t=1; - for(i=0; i<0x10; i++) - if (entry[i] != 0xff) - t=0; - if (t) - return MPIO_BLOCK_FREE; - - /* check for "strange" errors */ - if ((entry[6] != entry[11]) || - (entry[7] != entry[12])) - { - debug("error: different block addresses found:\n"); - hexdumpn(1, entry, 0x10); - return MPIO_BLOCK_DEFECT; - } - - ba = entry[6] * 0x100 + entry[7]; - - /* special values */ - if (ba == 0xffff) - return MPIO_BLOCK_DEFECT; - if (ba == 0x0000) - return MPIO_BLOCK_CIS; - - /* check parity */ - value = ba; - while (value) - { - if (value & 0x01) - p ^= 0x01; - - value /= 2; - } - if (p) - { - debug("parity error found in block address: %2x\n", ba); - return MPIO_BLOCK_DEFECT; - } - - high = ((ba / 0x100) & 0x07); - low = ((ba & 0x0ff) / 2); - - return (high * 0x80 + low); -} - -/* foobar */ - -void -fatentry2hw(mpio_fatentry_t *f, BYTE *chip, DWORD *address) -{ - mpio_smartmedia_t *sm; - - if (f->mem == MPIO_INTERNAL_MEM) - { - sm = &f->m->internal; - /* hexdump((char *)&f->entry, 4); */ - /* hexdump((char *)&f->hw_address, 4); */ - *chip = f->hw_address / 0x1000000; - *address = f->hw_address & 0x0ffffff; - } - if (f->mem == MPIO_EXTERNAL_MEM) - { - sm = &f->m->external; - *chip = MPIO_EXTERNAL_MEM; - *address = mpio_zone_block_find_log(f->m, f->mem, f->entry); - debugn(3, "mager: %06x (logical: %04x)\n", *address, f->entry); - } - return; -} - -/* - * zone management - */ - -int -mpio_zone_init(mpio_t *m, mpio_cmd_t mem) -{ - mpio_smartmedia_t *sm; - int i; - int zone, block, e; - - if (mem != MPIO_EXTERNAL_MEM) - { - debug("called function with wrong memory selection!\n"); - return -1; - } - sm = &m->external; - - for(i=0; imax_blocks; i++) - { - zone = i / MPIO_ZONE_PBLOCKS; - block= i % MPIO_ZONE_PBLOCKS; - - e = i * 0x10; - - sm->zonetable[zone][block]=blockaddress_decode(sm->spare+e); - - hexdumpn(4, sm->spare+e, 0x10); - debugn(2, "decoded: %04x\n", sm->zonetable[zone][block]); - } - -} - -DWORD -mpio_zone_block_find_log(mpio_t *m, mpio_cmd_t mem, DWORD lblock) -{ - mpio_smartmedia_t *sm; - int v; - - if (mem != MPIO_EXTERNAL_MEM) - { - debug("called function with wrong memory selection!\n"); - return -1; - } - sm = &m->external; - - /* OK, I can't explain this right now, but it does work, - * see Software Driver v3.0, page 31 - */ - v = lblock + (sm->size/64); - - return (mpio_zone_block_find_seq(m, mem, v)); -} - -DWORD -mpio_zone_block_find_seq(mpio_t *m, mpio_cmd_t mem, DWORD lblock) -{ - mpio_smartmedia_t *sm; - int i, f, v; - int zone, block; - - if (mem != MPIO_EXTERNAL_MEM) - { - debug("called function with wrong memory selection!\n"); - return -1; - } - sm = &m->external; - - if ((lblock>=MPIO_BLOCK_CIS) && (lblock<(MPIO_BLOCK_CIS + BLOCK_SECTORS))) - { - zone = 0; - block = MPIO_BLOCK_CIS; - } else { - zone = lblock / MPIO_ZONE_LBLOCKS; - block = lblock % MPIO_ZONE_LBLOCKS; - } - - f=0; - for (i=(MPIO_ZONE_PBLOCKS-1); i >=0; i--) - { - - if (sm->zonetable[zone][i]==block) - { - f++; - v=i; - } - } - - if (f>1) - debug("found more than one block, using first one\n"); - - if (!f) - { - debugn(2, "block not found\n"); - return MPIO_BLOCK_NOT_FOUND; - } - - return ((zone * BLOCK_SECTORS * MPIO_ZONE_PBLOCKS ) + v * BLOCK_SECTORS); -} - -DWORD -mpio_zone_block_set_free(mpio_t *m, mpio_cmd_t mem, DWORD lblock) -{ - DWORD value; - int zone, block; - mpio_smartmedia_t *sm; - - if (mem != MPIO_EXTERNAL_MEM) - { - debug("called function with wrong memory selection!\n"); - return -1; - } - sm = &m->external; - - value = mpio_zone_block_find_log(m, mem, lblock); - - mpio_zone_block_set_free_phys(m, mem, value); - - return value; -} - -void -mpio_zone_block_set_free_phys(mpio_t *m, mpio_cmd_t mem, DWORD value) -{ - int zone, block; - mpio_smartmedia_t *sm; - - if (mem != MPIO_EXTERNAL_MEM) - { - debug("called function with wrong memory selection!\n"); - return; - } - sm = &m->external; - - zone = value / BLOCK_SECTORS; - block = zone % MPIO_ZONE_PBLOCKS; - zone = zone / MPIO_ZONE_PBLOCKS; - - sm->zonetable[zone][block] = MPIO_BLOCK_FREE; - - return; -} - -void -mpio_zone_block_set_defect_phys(mpio_t *m, mpio_cmd_t mem, DWORD value) -{ - int zone, block; - mpio_smartmedia_t *sm; - - if (mem != MPIO_EXTERNAL_MEM) - { - debug("called function with wrong memory selection!\n"); - return; - } - sm = &m->external; - - zone = value / BLOCK_SECTORS; - block = zone % MPIO_ZONE_PBLOCKS; - zone = zone / MPIO_ZONE_PBLOCKS; - - sm->zonetable[zone][block] = MPIO_BLOCK_DEFECT; - - return; -} - -void -mpio_zone_block_set(mpio_t *m, mpio_cmd_t mem, DWORD pblock) -{ - int zone, block, pb; - - pb = pblock / BLOCK_SECTORS; - zone = pb / MPIO_ZONE_PBLOCKS; - block = pb % MPIO_ZONE_PBLOCKS; - - m->external.zonetable[zone][block] = MPIO_BLOCK_FREE ; - -} - -DWORD -mpio_zone_block_find_free_log(mpio_t *m, mpio_cmd_t mem, DWORD lblock) -{ - mpio_smartmedia_t *sm; - int v; - - if (mem != MPIO_EXTERNAL_MEM) - { - debug("called function with wrong memory selection!\n"); - return -1; - } - sm = &m->external; - - /* OK, I can't explain this right now, but it does work, - * see Software Driver v3.0, page 31 - */ - v = lblock + (sm->size/64); - - return (mpio_zone_block_find_free_seq(m, mem, v)); -} - -DWORD -mpio_zone_block_find_free_seq(mpio_t *m, mpio_cmd_t mem, DWORD lblock) -{ - DWORD value; - int zone, block, i; - mpio_smartmedia_t *sm; - - if (mem != MPIO_EXTERNAL_MEM) - { - debug("called function with wrong memory selection!\n"); - return -1; - } - sm = &m->external; - - value = mpio_zone_block_find_seq(m, mem, lblock); - - if (value != MPIO_BLOCK_NOT_FOUND) - { - debug("logical block numbers is already assigned! (%4x)\n", lblock); - exit (-1); - } - - if ((lblock>=MPIO_BLOCK_CIS) && (lblock<(MPIO_BLOCK_CIS + BLOCK_SECTORS))) - { - zone = 0; - block = MPIO_BLOCK_CIS; - } else { - zone = lblock / MPIO_ZONE_LBLOCKS; - block = lblock % MPIO_ZONE_LBLOCKS; - } - - i=0; - while ((sm->zonetable[zone][i]!=MPIO_BLOCK_FREE) && (izonetable[zone][i] = block; - - return ((zone * BLOCK_SECTORS * MPIO_ZONE_PBLOCKS ) + i * BLOCK_SECTORS); -} - - -WORD -mpio_zone_block_get_logical(mpio_t *m, mpio_cmd_t mem, DWORD pblock) -{ - int zone, block, pb; - - pb = pblock / BLOCK_SECTORS; - zone = pb / MPIO_ZONE_PBLOCKS; - block = pb % MPIO_ZONE_PBLOCKS; - - return m->external.zonetable[zone][block]; -} - - - - - -/* - * low-low level functions - */ - -/* - * Set command packet - * - * parameter: - * - * cmd: commando code - * mem: internal/external - * index: sector/block - * size: size of used memory chip - * wsize: write size, only for PUT_BLOCK - * buffer: output buffer of command packet - * - */ - -int -mpio_io_set_cmdpacket(mpio_t *m, mpio_cmd_t cmd, mpio_mem_t mem, DWORD index, - WORD size, BYTE wsize, BYTE *buffer) -{ - BYTE memory; - - /* clear cmdpacket*/ - memset(buffer, 0, 0x40); - - *buffer = cmd; - memory = mem; - if (mem == MPIO_EXTERNAL_MEM) - memory = model2externalmem(m->model); - - *(buffer + 0x01) = memory; - *(buffer + 0x03) = (BYTE) (index & 0x00ff); - *(buffer + 0x04) = (BYTE)((index & 0xff00) >> 8); - /* SM cards with less or equal 32 MB only need 2 Bytes - * to address sectors or blocks. - * The highest byte has to be 0xff in that case! - */ - if (size <= 32) - { - *(buffer + 0x05) = 0xff; - } else { - *(buffer + 0x05) = (BYTE) (index >> 16); - } - /* is this always 0x48 in case of a block write ?? */ - *(buffer + 0x06) = wsize; - - memcpy((buffer + 0x3b), "jykim", 5); - - return (0); -} - -/* - * write chunk of data to MPIO filedescriptor - * - * parameter: - * - * fd: filedescriptor - * block: data buffer (has to be num_bytes) - * num_bytes: size of data buffer - * - */ -int -mpio_io_bulk_write(int fd, BYTE *block, int num_bytes) -{ - BYTE *p; - int count, bytes_left, bytes_written; - - bytes_left = num_bytes; - bytes_written = 0; - p = block; - - do - { - count = write (fd, p, bytes_left); - if (count > 0) - { - p += count; - bytes_written += count; - bytes_left -= count; - } - } while (bytes_left > 0 && count > 0); - - return bytes_written; -} - -/* - * read chunk of data from MPIO filedescriptor - * - * parameter: - * - * fd: filedescriptor - * block: return buffer (has to be num_bytes) - * num_bytes: size of return buffer - * - */ -int -mpio_io_bulk_read (int fd, BYTE *block, int num_bytes) -{ - int total_read, count, bytes_left; - BYTE *p; - - total_read = 0; - bytes_left = num_bytes; - p = block; - - do - { - count = read (fd, p, bytes_left); - - if (count > 0) - { - total_read += count; - bytes_left -= count; - p += count; - } - } while (total_read < num_bytes && count > 0); - - return total_read; -} - -/* - * low level functions - */ - -/* - * read version block from MPIO - * - * parameter: - * - * m: mpio context - * buffer: return buffer (has to be CMD_SIZE) - * - */ -int -mpio_io_version_read(mpio_t *m, BYTE *buffer) -{ - int nwrite, nread; - BYTE cmdpacket[CMD_SIZE], status[CMD_SIZE]; - - /* Send command packet to MPIO */ - mpio_io_set_cmdpacket (m, GET_VERSION, 0, 0, 0xff, 0, cmdpacket); - - debugn (5, ">>> MPIO\n"); - hexdump (cmdpacket, sizeof(cmdpacket)); - - nwrite = mpio_io_bulk_write (m->fd, cmdpacket, 0x40); - - if (nwrite != CMD_SIZE) - { - debug ("Failed to send command.\n\n"); - close (m->fd); - return 0; - } - - /* Receive packet from MPIO */ - nread = mpio_io_bulk_read (m->fd, status, 0x40); - - if (nread == -1 || nread != 0x40) - { - debug ("Failed to read Sector.\n%x\n",nread); - close (m->fd); - return 0; - } - - debugn (5, "<<< MPIO\n"); - hexdump (status, 0x40); - - memcpy(buffer, status, 0x40); - - return CMD_SIZE; -} - -/* - * read sector from SmartMedia - * - * parameter: - * - * m: mpio context - * mem: MPIO_{INTERNAL,EXTERNAL}_MEM - * index: index number of sector to read - * output: return buffer (has to be SECTOR_SIZE) - * - */ - -/* right now we assume we only want to read single sectors from - * the _first_ internal memory chip - */ - -int -mpio_io_sector_read(mpio_t *m, BYTE mem, DWORD index, BYTE *output) -{ - mpio_smartmedia_t *sm=0; - DWORD sector; - int nwrite, nread; - BYTE cmdpacket[CMD_SIZE], recvbuff[SECTOR_TRANS]; - - if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; - if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; - if (!sm) - { - debug("error in memory selection, aborting\n"); - exit (-1); - } - - if (mem == MPIO_INTERNAL_MEM) - { - sector = index; - } else { - /* find the correct physical block first! */ - if ((index>=MPIO_BLOCK_CIS) && (index<(MPIO_BLOCK_CIS + BLOCK_SECTORS))) - { - sector = mpio_zone_block_find_seq(m, mem, MPIO_BLOCK_CIS); - sector+= (index % MPIO_BLOCK_CIS); - } else { - sector = mpio_zone_block_find_seq(m, mem, (index / 0x20)); - sector+= (index % 0x20); - } - } - - debugn (2, "sector: %8x (%06x)\n", index, sector); - - mpio_io_set_cmdpacket (m, GET_SECTOR, mem, sector, sm->size, 0, cmdpacket); - - debugn (5, "\n>>> MPIO\n"); - hexdump (cmdpacket, sizeof(cmdpacket)); - - nwrite = mpio_io_bulk_write (m->fd, cmdpacket, 0x40); - - if(nwrite != CMD_SIZE) - { - debug ("\nFailed to send command.\n\n"); - close (m->fd); - return 1; - } - - /* Receive packet from MPIO */ - nread = mpio_io_bulk_read (m->fd, recvbuff, SECTOR_TRANS); - - if(nread != SECTOR_TRANS) - { - debug ("\nFailed to read Sector.\n%x\n", nread); - close (m->fd); - return 1; - } - - /* check ECC Area information */ - if (mem==MPIO_EXTERNAL_MEM) - { - if (mpio_ecc_256_check (recvbuff, - (recvbuff + SECTOR_SIZE + 13)) || - mpio_ecc_256_check ((recvbuff + (SECTOR_SIZE / 2)), - (recvbuff + SECTOR_SIZE + 8)) ) - debug ("ECC error @ (%02x : %06x)\n", mem, index); - } - - /* This should not be needed: - * we don't have ECC information for the internal memory - * we only read the directory through this function - */ - /* if (mem==MPIO_INTERNAL_MEM) */ - /* { */ - /* debugn(2, "WARNING, code for internal FAT entry (in ECC area)" */ - /* " not yet in place!!\n"); */ - /* } */ - - debugn (5, "\n<<< MPIO\n"); - hexdump (recvbuff, SECTOR_TRANS); - - memcpy(output, recvbuff, SECTOR_SIZE); - - return 0; -} - -/* - * write sector to SmartMedia - * - * parameter: - * - * m: mpio context - * mem: MPIO_{INTERNAL,EXTERNAL}_MEM - * index: index number of sector to read - * input: data buffer (has to be SECTOR_SIZE) - * - */ - -/* right now we assume we only want to write single sectors from - * the _first_ internal memory chip - */ - -int -mpio_io_sector_write(mpio_t *m, BYTE mem, DWORD index, BYTE *input) -{ - int nwrite; - mpio_smartmedia_t *sm; - DWORD pvalue; - DWORD block_address, ba; - BYTE cmdpacket[CMD_SIZE], sendbuff[SECTOR_TRANS]; - - if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; - if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; - if (!sm) - { - debug("error in memory selection, aborting\n"); - exit (-1); - } - - /* we have to: - * - find the physical block (or allocate a new one) - * - calculate the logical block for zone management - */ - - if (mem == MPIO_EXTERNAL_MEM) - { - if (index==MPIO_BLOCK_DEFECT) - { - block_address = 0; - pvalue = 0; - } else { - if ((index>=MPIO_BLOCK_CIS) && - (index<(MPIO_BLOCK_CIS + BLOCK_SECTORS))) - { - block_address = 0; - if (index==MPIO_BLOCK_CIS) - { - pvalue=mpio_zone_block_find_free_seq(m, mem, index); - } else { - /* find the block from the block list! */ - pvalue=mpio_zone_block_find_seq(m, mem, MPIO_BLOCK_CIS); - } - if (pvalue != MPIO_BLOCK_NOT_FOUND) - pvalue = pvalue + index - MPIO_BLOCK_CIS; - - } else { - block_address = blockaddress_encode(index / BLOCK_SECTORS); - if ((index % BLOCK_SECTORS) == 0) - { - /* this is the first write to the block: allocate a new one */ - /* ... and mark it with the block_address */ - pvalue=mpio_zone_block_find_free_seq(m, mem, - (index / BLOCK_SECTORS)); - } else { - /* find the block from the block list! */ - pvalue=mpio_zone_block_find_seq(m, mem, (index / BLOCK_SECTORS)); - } - if (pvalue != MPIO_BLOCK_NOT_FOUND) - pvalue = pvalue + (index % BLOCK_SECTORS); - - } - - if (pvalue == MPIO_BLOCK_NOT_FOUND) - { - debug ("Oops, this should never happen! (%6x : %6x)\n", - index, block_address); - exit (-1); - } - } - } else { - pvalue = index; - } - - mpio_io_set_cmdpacket(m, PUT_SECTOR, mem, pvalue, sm->size, 0, cmdpacket); - - debugn (5, "\n>>> MPIO\n"); - hexdump (cmdpacket, sizeof(cmdpacket)); - - nwrite = mpio_io_bulk_write(m->fd, cmdpacket, 0x40); - - if(nwrite != CMD_SIZE) - { - debug ("\nFailed to send command.\n\n"); - close (m->fd); - return 1; - } - - memset(sendbuff, 0, SECTOR_TRANS); - memset(sendbuff + SECTOR_SIZE, 0xff, 0x10); - memcpy(sendbuff, input, SECTOR_SIZE); - - if (mem==MPIO_EXTERNAL_MEM) - { - if (index == MPIO_BLOCK_DEFECT) { - memset(sendbuff + SECTOR_SIZE, 0, 0x10); - mpio_zone_block_set_defect_phys(m, mem, pvalue); - } else { - - /* generate ECC information for spare area ! */ - mpio_ecc_256_gen(sendbuff, - sendbuff + SECTOR_SIZE + 0x0d); - mpio_ecc_256_gen(sendbuff + (SECTOR_SIZE / 2), - sendbuff + SECTOR_SIZE + 0x08); - if (index == MPIO_BLOCK_DEFECT) { - memset(sendbuff + SECTOR_SIZE, 0, 0x10); - } else { - if (index == MPIO_BLOCK_CIS) { - memset(sendbuff + SECTOR_SIZE + 0x06, 0, 2); - memset(sendbuff + SECTOR_SIZE + 0x0b, 0, 2); - } else { - ba = (block_address / 0x100) & 0xff; - sendbuff[SECTOR_SIZE + 0x06] = ba; - sendbuff[SECTOR_SIZE + 0x0b] = ba; - - ba = block_address & 0xff; - sendbuff[SECTOR_SIZE + 0x07] = ba; - sendbuff[SECTOR_SIZE + 0x0c] = ba; - } - } - - } - } - - /* easy but working, we write back the FAT info we read before */ - if (mem==MPIO_INTERNAL_MEM) - memcpy((sendbuff+SECTOR_SIZE), sm->fat, 0x10); - - debugn (5, "\n>>> MPIO\n"); - hexdump(sendbuff, SECTOR_TRANS); - - /* write sector MPIO */ - nwrite = mpio_io_bulk_write(m->fd, sendbuff, SECTOR_TRANS); - - if(nwrite != SECTOR_TRANS) - { - debug ("\nFailed to read Sector.\n%x\n", nwrite); - close (m->fd); - return 1; - } - - return 0; -} - -/* - * read/write of blocks - */ -int -mpio_io_block_read(mpio_t *m, mpio_mem_t mem, mpio_fatentry_t *f, BYTE *output) -{ - int i=0; - int nwrite, nread; - mpio_smartmedia_t *sm; - BYTE chip; - DWORD address; - BYTE cmdpacket[CMD_SIZE], recvbuff[BLOCK_TRANS]; - - if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; - if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; - - fatentry2hw(f, &chip, &address); - - mpio_io_set_cmdpacket(m, GET_BLOCK, chip, address, sm->size, 0, cmdpacket); - - debugn(5, "\n>>> MPIO\n"); - hexdump(cmdpacket, sizeof(cmdpacket)); - - nwrite = mpio_io_bulk_write(m->fd, cmdpacket, CMD_SIZE); - - if(nwrite != CMD_SIZE) - { - debug ("\nFailed to send command.\n\n"); - close (m->fd); - return 1; - } - - /* Receive packet from MPIO */ - nread = mpio_io_bulk_read(m->fd, recvbuff, BLOCK_TRANS); - - if(nread != BLOCK_TRANS) - { - debug ("\nFailed to read Block.\n%x\n",nread); - close (m->fd); - return 1; - } - - debugn(5, "\n<<< MPIO\n"); - hexdump(recvbuff, BLOCK_TRANS); - - for (i = 0; i < BLOCK_SECTORS; i++) - { - /* check ECC Area information */ - if (mem==MPIO_EXTERNAL_MEM) { - if (mpio_ecc_256_check ((recvbuff + (i * SECTOR_TRANS)), - ((recvbuff +(i * SECTOR_TRANS) - + SECTOR_SIZE +13))) || - mpio_ecc_256_check ((recvbuff + (i * SECTOR_TRANS) - + (SECTOR_SIZE / 2)), - ((recvbuff +(i * SECTOR_TRANS) - + SECTOR_SIZE + 8)))) - debug ("ECC error @ (%02x : %06x)\n", chip, address); - } - - memcpy(output + (i * SECTOR_SIZE), - recvbuff + (i * SECTOR_TRANS), - SECTOR_SIZE); - } - - return 0; -} - -/* Read spare is only usefull for the internal memory, - * the FAT lies there. It is updated during the - * mpio_io_{sector,block}_{read,write} operations. - * - * For external SmartMedia cards we have a "seperate" FAT - * which is read and updated just like on a regular floppy - * disc or hard drive. - * - */ - -int -mpio_io_spare_read(mpio_t *m, BYTE mem, DWORD index, WORD size, - BYTE wsize, BYTE *output, int toread, - mpio_callback_init_t progress_callback) -{ - mpio_smartmedia_t *sm; - int i; - int nwrite, nread; - int chip = 0; - int chips = 0; - BYTE cmdpacket[CMD_SIZE]; - - if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; - if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; - - chips = sm->chips; - - for (chip = 1; chip <= chips; chip++) - { - if (mem == MPIO_INTERNAL_MEM) - mpio_io_set_cmdpacket(m, GET_SPARE_AREA, (1 << (chip-1)), - index, (size / sm->chips), - wsize, cmdpacket); - if (mem == MPIO_EXTERNAL_MEM) - mpio_io_set_cmdpacket(m, GET_SPARE_AREA, mem, index, size, - wsize, cmdpacket); - debugn(5, "\n>>> MPIO\n"); - hexdump(cmdpacket, sizeof(cmdpacket)); - - nwrite = mpio_io_bulk_write(m->fd, cmdpacket, CMD_SIZE); - - if(nwrite != CMD_SIZE) { - debug ("\nFailed to send command.\n\n"); - close (m->fd); - return 1; - } - - /* Receive packet from MPIO */ - for (i = 0; i < (toread / chips / CMD_SIZE); i++) - { - nread = mpio_io_bulk_read (m->fd, - output + (i * CMD_SIZE) + - (toread / chips * (chip - 1)), - CMD_SIZE); - - if ((progress_callback) && (i % 256)) - (*progress_callback)(mem, - (i*CMD_SIZE+(toread/chips*(chip-1))), - toread ); - - if(nread != CMD_SIZE) - { - debug ("\nFailed to read Block.\n%x\n",nread); - close (m->fd); - return 1; - } - debugn(5, "\n<<< MPIO\n"); - hexdump(output + (i * CMD_SIZE) + (toread / chips * (chip - 1)), - CMD_SIZE); - } - } - if (progress_callback) - (*progress_callback)(mem, toread, toread); - - return 0; -} - -int -mpio_io_block_delete(mpio_t *m, mpio_mem_t mem, mpio_fatentry_t *f) -{ - BYTE chip=0; - DWORD address; - mpio_smartmedia_t *sm; - - if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; - if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; - - fatentry2hw(f, &chip, &address); - - if (address == MPIO_BLOCK_NOT_FOUND) - { - debug("hmm, what happens here? (%4x)\n", f->entry); - return 0; - } - - return (mpio_io_block_delete_phys(m, chip, address)); -} - -int -mpio_io_block_delete_phys(mpio_t *m, BYTE chip, DWORD address) -{ - mpio_smartmedia_t *sm; - int nwrite, nread; - BYTE cmdpacket[CMD_SIZE], status[CMD_SIZE]; - - /* Send command packet to MPIO */ - - if (chip == MPIO_INTERNAL_MEM) sm = &m->internal; - /* hack to support 2+4 internal chips - * who ever allowed me to write code??? -mager - */ - if (chip == (MPIO_INTERNAL_MEM+1)) sm = &m->internal; - if (chip == (MPIO_INTERNAL_MEM+3)) sm = &m->internal; - if (chip == (MPIO_INTERNAL_MEM+7)) sm = &m->internal; - if (chip == MPIO_EXTERNAL_MEM) - { - sm = &m->external; - mpio_zone_block_set_free_phys(m, chip, address); - } - - mpio_io_set_cmdpacket(m, DEL_BLOCK, chip, address, sm->size, 0, cmdpacket); - - debugn (5, ">>> MPIO\n"); - hexdump (cmdpacket, sizeof(cmdpacket)); - - nwrite = mpio_io_bulk_write(m->fd, cmdpacket, 0x40); - - if (nwrite != CMD_SIZE) - { - debug ("Failed to send command.\n\n"); - close (m->fd); - return 0; - } - -/* Receive packet from MPIO */ - nread = mpio_io_bulk_read (m->fd, status, CMD_SIZE); - - if ((nread == -1) || (nread != CMD_SIZE)) - { - debug ("Failed to read Sector.\n%x\n",nread); - close (m->fd); - return 0; - } - - debugn(5, "<<< MPIO\n"); - hexdump(status, CMD_SIZE); - - if (status[0] != 0xc0) - { - debugn (2,"error formatting Block %02x:%06x\n", - chip, address); - if (chip == MPIO_EXTERNAL_MEM) - { - sm = &m->external; - mpio_zone_block_set_defect_phys(m, chip, address); - } - } - - return CMD_SIZE; -} - -int -mpio_io_block_write(mpio_t *m, mpio_mem_t mem, mpio_fatentry_t *f, BYTE *data) -{ - mpio_smartmedia_t *sm; - int nwrite; - int i; - DWORD block_address, ba; - BYTE cmdpacket[CMD_SIZE], sendbuff[BLOCK_TRANS]; - BYTE chip=0; - DWORD address; - - if (mem == MPIO_INTERNAL_MEM) - { - sm = &m->internal; - fatentry2hw(f, &chip, &address); - } - - if (mem == MPIO_EXTERNAL_MEM) - { - sm = &m->external; - /* find free physical block */ - chip = MPIO_EXTERNAL_MEM; - address = mpio_zone_block_find_free_log(m, mem, f->entry); - } - - /* build block for transfer to MPIO */ - for (i = 0; i < BLOCK_SECTORS; i++) - { - memcpy(sendbuff + (i * SECTOR_TRANS), - data + (i * SECTOR_SIZE), - SECTOR_SIZE); - memset(sendbuff + (i * SECTOR_TRANS) + SECTOR_SIZE, - 0xff, CMD_SIZE); - - if (mem == MPIO_INTERNAL_MEM) - { - if (i == 0) - { - memcpy((sendbuff+SECTOR_SIZE+(i * SECTOR_TRANS)), - f->i_fat, 0x10); -/* debug("address %02x:%06x\n", chip, address); */ -/* hexdumpn(0, f->i_fat, 0x10); */ - } - } - - /* fill in block information */ - if (mem == MPIO_EXTERNAL_MEM) - { - block_address = mpio_zone_block_get_logical(m, mem, address); - block_address = blockaddress_encode(block_address); - - ba = (block_address / 0x100) & 0xff; - sendbuff[(i * SECTOR_TRANS) + SECTOR_SIZE + 0x06] = ba; - sendbuff[(i * SECTOR_TRANS) + SECTOR_SIZE + 0x0b] = ba; - - ba = block_address & 0xff; - sendbuff[(i * SECTOR_TRANS) + SECTOR_SIZE + 0x07] = ba; - sendbuff[(i * SECTOR_TRANS) + SECTOR_SIZE + 0x0c] = ba; - - /* generate ECC Area information */ - mpio_ecc_256_gen ((sendbuff + (i * SECTOR_TRANS)), - ((sendbuff + (i * SECTOR_TRANS) - + SECTOR_SIZE + 13))); - mpio_ecc_256_gen ((sendbuff + (i * SECTOR_TRANS) - + (SECTOR_SIZE / 2)), - ((sendbuff + (i * SECTOR_TRANS) - + SECTOR_SIZE + 8))); - } - } - - mpio_io_set_cmdpacket(m, PUT_BLOCK, chip, address, sm->size, 0x48 , cmdpacket); - - debugn(5, "\n>>> MPIO\n"); - hexdump(cmdpacket, sizeof(cmdpacket)); - - nwrite = mpio_io_bulk_write(m->fd, cmdpacket, CMD_SIZE); - - if(nwrite != CMD_SIZE) - { - debug ("\nFailed to send command.\n\n"); - close (m->fd); - return 1; - } - - /* send packet to MPIO */ - debugn(5, "\n<<< MPIO\n"); - hexdump(sendbuff, BLOCK_TRANS); - nwrite = mpio_io_bulk_write (m->fd, sendbuff, BLOCK_TRANS); - - if(nwrite != BLOCK_TRANS) - { - debug ("\nFailed to read Block.\n%x\n",nwrite); - close (m->fd); - return 1; - } - - return 0; -} diff --git a/libmpio/io.h b/libmpio/io.h deleted file mode 100644 index 1c2baf9..0000000 --- a/libmpio/io.h +++ /dev/null @@ -1,95 +0,0 @@ -/* -*- linux-c -*- */ - -/* - * - * $Id: io.h,v 1.13 2003/04/04 22:03:05 germeier Exp $ - * - * Library for USB MPIO-* - * - * Markus Germeier (mager@tzi.de) - * - * uses code from mpio_stat.c by - * Yuji Touya (salmoon@users.sourceforge.net) - * - * - * 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. - * - * */ - -#ifndef _MPIO_IO_H_ -#define _MPIO_IO_H_ - -#include "defs.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* phys.<->log. block mapping */ -int mpio_zone_init(mpio_t *, mpio_cmd_t); -/* context, memory bank, logical block */ -/* returns address of physical block! */ -DWORD mpio_zone_block_find_log(mpio_t *, mpio_cmd_t, DWORD); - /* context, memory bank, sequential block (for sector addressing) */ -/* returns address of physical block! */ -DWORD mpio_zone_block_find_seq(mpio_t *, mpio_cmd_t, DWORD); -/* context, memory bank, logical block */ -/* find used physical block and mark it as unused! */ -/* returns address of physical block! (to delete the physical block!) */ -DWORD mpio_zone_block_set_free(mpio_t *, mpio_cmd_t, DWORD); -/* context, memory bank, physical block */ -void mpio_zone_block_set_free_phys(mpio_t *, mpio_cmd_t, DWORD); -/* context, memory bank, physical block */ -void mpio_zone_block_set_defect_phys(mpio_t *, mpio_cmd_t, DWORD); -/* context, memory bank, logical block */ -/* looks for a free physical block to be used for given logical block */ -/* mark the found block used for this logical block */ -/* returns address of physical block! */ -DWORD mpio_zone_block_find_free_log(mpio_t *, mpio_cmd_t, DWORD); -DWORD mpio_zone_block_find_free_seq(mpio_t *, mpio_cmd_t, DWORD); -/* return zone-logical block for a given physical block */ -WORD mpio_zone_block_get_logical(mpio_t *, mpio_cmd_t, DWORD); - - -/* real I/O */ -int mpio_io_set_cmdpacket(mpio_t *, mpio_cmd_t, mpio_mem_t, - DWORD, WORD, BYTE, BYTE *); - -int mpio_io_bulk_read (int, BYTE *, int); -int mpio_io_bulk_write(int, BYTE *, int); - -/* read version block into memory */ -int mpio_io_version_read(mpio_t *, BYTE *); - -/* */ -int mpio_io_sector_read (mpio_t *, BYTE, DWORD, BYTE *); -int mpio_io_sector_write(mpio_t *, BYTE, DWORD, BYTE *); - -/* */ -int mpio_io_block_read (mpio_t *, mpio_mem_t, mpio_fatentry_t *, BYTE *); -int mpio_io_block_write (mpio_t *, mpio_mem_t, mpio_fatentry_t *, BYTE *); -int mpio_io_block_delete(mpio_t *, mpio_mem_t, mpio_fatentry_t *); -/* needed for formatting of external memory */ -int mpio_io_block_delete_phys(mpio_t *, BYTE, DWORD); - -/* */ -int mpio_io_spare_read (mpio_t *, BYTE, DWORD, WORD, BYTE, BYTE *, int, - mpio_callback_init_t); - -#ifdef __cplusplus -} -#endif - -#endif /* _MPIO_IO_H_ */ diff --git a/libmpio/mpio.c b/libmpio/mpio.c deleted file mode 100644 index 04c3b58..0000000 --- a/libmpio/mpio.c +++ /dev/null @@ -1,1301 +0,0 @@ -/* - * - * $Id: mpio.c,v 1.53 2003/04/19 23:58:02 germeier Exp $ - * - * Library for USB MPIO-* - * - * Markus Germeier (mager@tzi.de) - * - * uses code from mpio_stat.c by - * Yuji Touya (salmoon@users.sourceforge.net) - * - * - * 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 -#include -#include -#include -#include -#include - -#include "cis.h" -#include "defs.h" -#include "debug.h" -#include "directory.h" -#include "io.h" -#include "mpio.h" -#include "smartmedia.h" -#include "fat.h" - -void mpio_bail_out(void); -void mpio_init_internal(mpio_t *); -void mpio_init_external(mpio_t *); -int mpio_check_filename(mpio_filename_t); - -int mpio_file_get_real(mpio_t *, mpio_mem_t, mpio_filename_t, mpio_filename_t, - mpio_callback_t, BYTE **); - -int mpio_file_put_real(mpio_t *, mpio_mem_t, mpio_filename_t, mpio_filename_t, - mpio_filetype_t, mpio_callback_t, BYTE *, int); - -static BYTE *mpio_model_name[] = { - "MPIO-DME", - "MPIO-DMG", - "MPIO-DMG+", - "MPIO-DMB", - "MPIO-DMB+", - "MPIO-DMK", - "MPIO-FD100", - "MPIO-FL100", - "MPIO-FY100", - "unknown" -}; - -static mpio_error_t mpio_errors[] = { - { MPIO_ERR_FILE_NOT_FOUND, - "The selected file can not be found." }, - { MPIO_ERR_NOT_ENOUGH_SPACE, - "There is not enough space left on the selected memory card." }, - { MPIO_ERR_FILE_EXISTS, - "The selected file already exists and can not be overwritten. Remove it first." }, - { MPIO_ERR_FAT_ERROR, - "Internal error while reading the FAT." }, - { MPIO_ERR_READING_FILE, - "The selected file can not be read." }, - { MPIO_ERR_PERMISSION_DENIED, - "There are not enough rights to access the file/directory." }, - { MPIO_ERR_WRITING_FILE, - "There are no permisson to write to the selected file." }, - { MPIO_ERR_DIR_TOO_LONG, - "The selected directory name is to long." }, - { MPIO_ERR_DIR_NOT_FOUND, - "The selected directory can not be found." }, - { MPIO_ERR_DIR_NOT_A_DIR, - "The selected directory is not a directory." }, - { MPIO_ERR_DIR_NAME_ERROR, - "The selected directory name is not allowed." }, - { MPIO_ERR_DIR_NOT_EMPTY, - "The selected directory is not empty." }, - { MPIO_ERR_DEVICE_NOT_READY, - "Could not open " MPIO_DEVICE "\n" - "Verify that the mpio module is loaded and " - "your MPIO is\nconnected and powered up.\n" }, - { MPIO_ERR_OUT_OF_MEMORY, - "Out of Memory." }, - { MPIO_ERR_INTERNAL, - "Oops, internal ERROR. :-(" }, - { MPIO_ERR_INT_STRING_INVALID, - "Internal Error: Supported is invalid!" } -}; - -static const int mpio_error_num = sizeof mpio_errors / sizeof(mpio_error_t); - -static int _mpio_errno = 0; - -#define MPIO_ERR_RETURN(err) { mpio_id3_end(m); _mpio_errno = err; return -1 ; } - -#define MPIO_CHECK_FILENAME(filename) \ - if (!mpio_check_filename(filename)) { \ - MPIO_ERR_RETURN(MPIO_ERR_INT_STRING_INVALID); \ - } - -void -mpio_bail_out(void){ - printf("I'm utterly confused and aborting now, sorry!"); - printf("Please report this to: mpio-devel@lists.sourceforge.net\n"); - exit(1); -} - -int -mpio_check_filename(mpio_filename_t filename) -{ - BYTE *p=filename; - - while (p < (filename + MPIO_FILENAME_LEN)) - { - if (*p) - return 1; - p++; - } - - return 0; -} - -void -mpio_init_internal(mpio_t *m) -{ - mpio_smartmedia_t *sm = &m->internal; - BYTE i_offset = 0x18; - - /* init main memory parameters */ - sm->manufacturer = m->version[i_offset]; - sm->id = m->version[i_offset + 1]; - sm->chips = 1; - if (!(mpio_id_valid(m->version[i_offset]))) - { - sm->manufacturer = 0; - sm->id = 0; - sm->size = 0; - debug("WARNING: no internal memory found\n"); - return; - } - - - /* look for further installed memory chips - * models with 1, 2 and 4 chips are known - * (there _really_ shouldn't be any other versions out there ...) - */ - while ((sm->chips < 4) && - (mpio_id_valid(m->version[i_offset + (2 * sm->chips)]))) - { - if(mpio_id2mem(sm->id) != - mpio_id2mem(m->version[i_offset + (2 * sm->chips) + 1])) - { - printf("Found a MPIO with internal chips of different sizes!"); - mpio_bail_out(); - } - sm->chips++; - } - - if ((sm->chips == 3) || (sm->chips > 4)) - { - printf("Found a MPIO with %d internal chips", sm->chips); - mpio_bail_out(); - } - - sm->size = sm->chips * mpio_id2mem(sm->id); - debugn(2, "found %d chip(s) with %d MB => %d MB internal mem\n", - sm->chips, mpio_id2mem(sm->id), sm->size); - - /* used for size calculations (see mpio_memory_free) */ - mpio_id2geo(sm->id, &sm->geo); - - /* read FAT information from spare area */ - sm->max_cluster = (sm->size * 1024) / 16; /* 1 cluster == 16 KB */ - sm->max_blocks = sm->max_cluster; - debugn(2, "max_cluster: %d\n", sm->max_cluster); - /* 16 bytes per cluster */ - sm->fat_size = (sm->max_cluster * 16) / SECTOR_SIZE; - debugn(2, "fat_size: %04x\n", sm->fat_size * SECTOR_SIZE); - sm->fat = malloc(sm->fat_size * SECTOR_SIZE); - /* fat will be read in mpio_init, so we can more easily handle - a callback function */ - - if (!(sm->fat_size)) - { - printf("Some values on the way to the FAT calculations did not compute. :-(\n"); - mpio_bail_out(); - } - - - /* Read directory from internal memory */ - sm->dir_offset=0; - sm->root = malloc (sizeof(mpio_directory_t)); - sm->root->name[0] = 0; - sm->root->next = NULL; - sm->root->prev = NULL; - mpio_rootdir_read(m, MPIO_INTERNAL_MEM); - sm->cdir = sm->root; -} - -void -mpio_init_external(mpio_t *m) -{ - mpio_smartmedia_t *sm = &(m->external); - BYTE e_offset = 0x20; - - /* heuristic to find the right offset for the external memory */ - while((e_offset < 0x3a) && !(mpio_id_valid(m->version[e_offset]))) - e_offset++; - - if ((mpio_id_valid(m->version[e_offset])) && - (m->model != MPIO_MODEL_FL100)) /* ignore external memory ATM until - we know how to support it! */ - { - sm->manufacturer = m->version[e_offset]; - sm->id = m->version[e_offset + 1]; - } else { - sm->manufacturer = 0; - sm->id = 0; - sm->chips = 0; - sm->size = 0; - } - - /* init memory parameters if external memory is found */ - if (sm->id != 0) - { - /* Read things from external memory (if available) */ - sm->size = mpio_id2mem(sm->id); - sm->chips = 1; /* external is always _one_ chip !! */ - - mpio_id2geo(sm->id, &sm->geo); - - if (sm->size < 16) - { - debug("Sorry, I don't believe this software works with " - "SmartMedia Cards less than 16MB\n" - "Proceed with care and send any findings to: " - "mpio-devel@lists.sourceforge.net\n"); - } - - /* for reading the spare area later! */ - sm->max_blocks = sm->size / 16 * 1024; /* 1 cluster == 16 KB */ - sm->spare = malloc(sm->max_blocks * 0x10); - } - - /* setup directory support */ - sm->dir_offset=0; - sm->root = malloc (sizeof(mpio_directory_t)); - sm->root->name[0] = 0; - sm->root->next = NULL; - sm->root->prev = NULL; - sm->cdir = sm->root; -} - -mpio_t * -mpio_init(mpio_callback_init_t progress_callback) -{ - mpio_t *new_mpio; - mpio_smartmedia_t *sm; - int id_offset; - BYTE i; - - new_mpio = malloc(sizeof(mpio_t)); - if (!new_mpio) { - debug ("Error allocating memory for mpio_t"); - return NULL; - } - memset(new_mpio, 0, sizeof(mpio_t)); - - new_mpio->fd = open(MPIO_DEVICE, O_RDWR); - - if (new_mpio->fd < 0) { - _mpio_errno = MPIO_ERR_DEVICE_NOT_READY; - return NULL; - } - - /* Read Version Information */ - mpio_io_version_read(new_mpio, new_mpio->version); - - /* fill in values */ - snprintf(new_mpio->firmware.id, 12, "%s", new_mpio->version); - /* fix for newer versions which have a 0x00 in their version */ - for (i=0x0c ; i<0x10 ; i++) - if (new_mpio->version[i] == 0x00) - new_mpio->version[i]=' '; - snprintf(new_mpio->firmware.major, 3, "%s", new_mpio->version + 0x0c); - snprintf(new_mpio->firmware.minor, 3, "%s", new_mpio->version + 0x0e); - snprintf(new_mpio->firmware.year, 5, "%s", new_mpio->version + 0x10); - snprintf(new_mpio->firmware.month, 3, "%s", new_mpio->version + 0x14); - snprintf(new_mpio->firmware.day, 3, "%s", new_mpio->version + 0x16); - - /* there are different identification strings! */ - if (strncmp(new_mpio->version, "MPIO", 4) == 0) { - /* strings: "MPIOxy " */ - id_offset = 4; - - /* string: "MPIO-xy " */ - if (new_mpio->version[id_offset] == '-') - id_offset++; - - /* identify different versions */ - switch (new_mpio->version[id_offset]) - { - case 'E': - new_mpio->model = MPIO_MODEL_DME; - break ; - case 'K': - new_mpio->model = MPIO_MODEL_DMK; - break ; - case 'G': - new_mpio->model = MPIO_MODEL_DMG; - if (new_mpio->version[id_offset+1] == 'P') - new_mpio->model = MPIO_MODEL_DMG_PLUS; - break ; - case 'B': - new_mpio->model = MPIO_MODEL_DMB; - if (new_mpio->version[id_offset+1] == 'P') - new_mpio->model = MPIO_MODEL_DMB_PLUS; - break; - default: - new_mpio->model = MPIO_MODEL_UNKNOWN; - } - } else if (strncmp(new_mpio->version, "FD100", 5) == 0) { - new_mpio->model = MPIO_MODEL_FD100; - } else if (strncmp(new_mpio->version, "FL100", 5) == 0) { - /* we assume this model is not supported */ - new_mpio->model = MPIO_MODEL_FL100; - debug("FL100 found: External memory is ignored, because we don't know how" - " to support it at the moment (MultiMediaCards instead of SmartMedia)\n"); - } else if (strncmp(new_mpio->version, "FY100", 5) == 0) { - new_mpio->model = MPIO_MODEL_FY100; - /* I assume this is like the FD100/FL100, I didn't had the chance to - look at a FY100 firmware yet. -mager */ - debug("FY100 found: Beware, this model is not tested and we don't know" - " if it does work!\n"); - } else { - new_mpio->model = MPIO_MODEL_UNKNOWN; - } - - if (new_mpio->model == MPIO_MODEL_UNKNOWN) { - debug("Unknown version string found!\n" - "Please report this to: mpio-devel@lists.sourceforge.net\n"); - hexdumpn(1, new_mpio->version, CMD_SIZE); - } - - /* internal init */ - mpio_init_internal(new_mpio); - - /* external init */ - mpio_init_external(new_mpio); - - /* read FAT/spare area */ - if (new_mpio->internal.id) - mpio_fat_read(new_mpio, MPIO_INTERNAL_MEM, progress_callback); - - /* read the spare area (for block mapping) */ - if (new_mpio->external.id) - { - sm = &new_mpio->external; - mpio_io_spare_read(new_mpio, MPIO_EXTERNAL_MEM, 0, - sm->size, 0, sm->spare, - (sm->max_blocks * 0x10), progress_callback); - mpio_zone_init(new_mpio, MPIO_EXTERNAL_MEM); - - /* card might be defect */ - if (mpio_bootblocks_read(new_mpio, MPIO_EXTERNAL_MEM)==0) - { - sm->fat = malloc(SECTOR_SIZE*sm->fat_size); - mpio_fat_read(new_mpio, MPIO_EXTERNAL_MEM, NULL); - mpio_rootdir_read(new_mpio, MPIO_EXTERNAL_MEM); - } - } - - /* set default charset for filename conversion */ - new_mpio->charset=strdup(MPIO_CHARSET); - - /* disable ID3 rewriting support */ - new_mpio->id3=0; - strncpy(new_mpio->id3_format, MPIO_ID3_FORMAT, INFO_LINE); - new_mpio->id3_temp[0]=0x00; - - return new_mpio; -} - -/* - * returns available memory - * - * free: give back free memory size - * - */ -int -mpio_memory_free(mpio_t *m, mpio_mem_t mem, int *free) -{ - if (mem==MPIO_INTERNAL_MEM) { - if (!m->internal.size) { - *free=0; - return 0; - } - *free=mpio_fat_free_clusters(m, mem); - return (m->internal.geo.SumSector - * SECTOR_SIZE / 1000 * m->internal.chips); - } - - if (mem==MPIO_EXTERNAL_MEM) { - if (!m->external.size) { - *free=0; - return 0; - } - *free=mpio_fat_free_clusters(m, mem); - return (m->external.geo.SumSector * SECTOR_SIZE / 1000); - } - - return 0; -} - -void -mpio_close(mpio_t *m) -{ - if (m) { - close(m->fd); - - if(m->internal.fat) - free(m->internal.fat); - if(m->external.fat) - free(m->external.fat); - - free(m); - } -} - -mpio_model_t -mpio_get_model(mpio_t *m) -{ - mpio_model_t r; - - if (m) - { - r = m->model; - } else { - r = MPIO_MODEL_UNKNOWN; - } - - return r; -} - -void -mpio_get_info(mpio_t *m, mpio_info_t *info) -{ - int max=INFO_LINE-1; - snprintf(info->firmware_id, max, "\"%s\"", m->firmware.id); - snprintf(info->firmware_version, max, "%s.%s", - m->firmware.major, m->firmware.minor); - snprintf(info->firmware_date, max, "%s.%s.%s", - m->firmware.day, m->firmware.month, m->firmware.year); - snprintf(info->model, max, "%s", mpio_model_name[m->model]); - - if (!m->internal.id) - { - snprintf(info->mem_internal, max, "not available"); - } else { - if (m->internal.chips == 1) - { - snprintf(info->mem_internal, max, "%3dMB (%s)", - mpio_id2mem(m->internal.id), - mpio_id2manufacturer(m->internal.manufacturer)); - } else { - snprintf(info->mem_internal, max, "%3dMB (%s) - %d chips", - mpio_id2mem(m->internal.id)*m->internal.chips, - mpio_id2manufacturer(m->internal.manufacturer), - m->internal.chips); - } - } - - if (m->external.id) - { - snprintf(info->mem_external, max, "%3dMB (%s)", - mpio_id2mem(m->external.id), - mpio_id2manufacturer(m->external.manufacturer)); - } else { - snprintf(info->mem_external, max, "not available"); - } - -} - - -int -mpio_file_get_as(mpio_t *m, mpio_mem_t mem, mpio_filename_t filename, - mpio_filename_t as, mpio_callback_t progress_callback) -{ - return mpio_file_get_real(m, mem, filename, as, progress_callback, NULL); -} - -int -mpio_file_get(mpio_t *m, mpio_mem_t mem, mpio_filename_t filename, - mpio_callback_t progress_callback) -{ - return mpio_file_get_real(m, mem, filename, NULL, progress_callback, NULL); -} - -int -mpio_file_get_to_memory(mpio_t *m, mpio_mem_t mem, mpio_filename_t filename, - mpio_callback_t progress_callback, BYTE **memory) -{ - return mpio_file_get_real(m, mem, filename, NULL, progress_callback, memory); -} - -int -mpio_file_get_real(mpio_t *m, mpio_mem_t mem, mpio_filename_t filename, - mpio_filename_t as, mpio_callback_t progress_callback, - BYTE **memory) -{ - mpio_smartmedia_t *sm; - BYTE block[BLOCK_SIZE]; - int fd, towrite; - BYTE *p; - mpio_fatentry_t *f = 0; - struct utimbuf utbuf; - long mtime; - DWORD filesize, fsize; - BYTE abort = 0; - int merror; - - MPIO_CHECK_FILENAME(filename); - - if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; - if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; - - if(as==NULL) { - as = filename; - } - - /* find file */ - p = mpio_dentry_find_name(m, mem, filename); - if (!p) - p = mpio_dentry_find_name_8_3(m, mem, filename); - - if (p) - f = mpio_dentry_get_startcluster(m, mem, p); - - if (f && p) { - filesize=fsize=mpio_dentry_get_filesize(m, mem, p); - - if (memory) - { - *memory = malloc(filesize); - } else { - unlink(filename); - fd = open(as, (O_RDWR | O_CREAT), (S_IRWXU | S_IRGRP | S_IROTH)); - } - - do - { - mpio_io_block_read(m, mem, f, block); - - if (filesize > BLOCK_SIZE) { - towrite = BLOCK_SIZE; - } else { - towrite = filesize; - } - - if (memory) - { - memcpy((*memory)+(fsize-filesize) , block, towrite); - } else { - if (write(fd, block, towrite) != towrite) { - debug("error writing file data\n"); - close(fd); - free (f); - MPIO_ERR_RETURN(MPIO_ERR_WRITING_FILE); - } - } - - filesize -= towrite; - - if (progress_callback) - abort=(*progress_callback)((fsize-filesize), fsize); - if (abort) - debug("aborting operation"); - - } while ((((merror=(mpio_fatentry_next_entry(m, mem, f)))>0) && - (filesize>0)) && (!abort)); - - if (merror<0) - debug("defective block encountered!\n"); - - if(!memory) - { - close (fd); - free (f); - } - - /* read and copied code from mtools-3.9.8/mcopy.c - * to make this one right - */ - mtime=mpio_dentry_get_time(m, mem, p); - utbuf.actime = mtime; - utbuf.modtime = mtime; - utime(filename, &utbuf); - - } else { - debugn(2, "unable to locate the file: %s\n", filename); - _mpio_errno=MPIO_ERR_FILE_NOT_FOUND; - } - - return (fsize-filesize); -} - -int -mpio_file_put_as(mpio_t *m, mpio_mem_t mem, mpio_filename_t filename, - mpio_filename_t as, mpio_filetype_t filetype, - mpio_callback_t progress_callback) -{ - return mpio_file_put_real(m, mem, filename, as, filetype, - progress_callback, NULL,0); -} - -int -mpio_file_put(mpio_t *m, mpio_mem_t mem, mpio_filename_t filename, - mpio_filetype_t filetype, mpio_callback_t progress_callback) -{ - return mpio_file_put_real(m, mem, filename, NULL, filetype, - progress_callback, NULL,0); -} - -int -mpio_file_put_from_memory(mpio_t *m, mpio_mem_t mem, mpio_filename_t filename, - mpio_filetype_t filetype, - mpio_callback_t progress_callback, - BYTE *memory, int memory_size) -{ - return mpio_file_put_real(m, mem, filename, NULL, filetype, - progress_callback, memory, memory_size); -} - -int -mpio_file_put_real(mpio_t *m, mpio_mem_t mem, mpio_filename_t i_filename, - mpio_filename_t o_filename, mpio_filetype_t filetype, - mpio_callback_t progress_callback, - BYTE *memory, int memory_size) -{ - mpio_smartmedia_t *sm; - mpio_fatentry_t *f, current, firstblock, backup; - WORD start; - BYTE block[BLOCK_SIZE]; - BYTE use_filename[INFO_LINE]; - int fd, toread; - struct stat file_stat; - struct tm tt; - time_t curr; - int id3; - - BYTE *p = NULL; - DWORD filesize, fsize, free, blocks; - BYTE abort = 0; - - if(o_filename == NULL) { - o_filename = i_filename; - } - - MPIO_CHECK_FILENAME(o_filename); - - if (mem==MPIO_INTERNAL_MEM) sm=&m->internal; - if (mem==MPIO_EXTERNAL_MEM) sm=&m->external; - - if (memory) - { - fsize=filesize=memory_size; - } else { - id3 = mpio_id3_do(m, i_filename, use_filename); - if (!id3) - strncat(use_filename, i_filename, INFO_LINE); - if (stat((const char *)use_filename, &file_stat)!=0) { - debug("could not find file: %s\n", use_filename); - MPIO_ERR_RETURN(MPIO_ERR_FILE_NOT_FOUND); - } - fsize=filesize=file_stat.st_size; - debugn(2, "filesize: %d\n", fsize); - } - - /* check if there is enough space left */ - mpio_memory_free(m, mem, &free); - if (free*1024entry; - } - - /* find file-id for internal memory */ - if (mem==MPIO_INTERNAL_MEM) - { - f->i_index=mpio_fat_internal_find_fileindex(m); - debugn(2, "fileindex: %02x\n", f->i_index); - f->i_fat[0x01]= f->i_index; - if (m->model >= MPIO_MODEL_FD100) - f->i_fat[0x0e] = f->i_index; - start = f->i_index; - - /* number of blocks needed for file */ - blocks = filesize / 0x4000; - if (filesize % 0x4000) - blocks++; - debugn(2, "blocks: %02x\n", blocks); - f->i_fat[0x02]=(blocks / 0x100) & 0xff; - f->i_fat[0x03]= blocks & 0xff; - } - - if (!memory) - { - /* open file for reading */ - fd = open(use_filename, O_RDONLY); - if (fd==-1) - { - debug("could not open file: %s\n", use_filename); - MPIO_ERR_RETURN(MPIO_ERR_FILE_NOT_FOUND); - } - } - - while ((filesize>BLOCK_SIZE) && (!abort)) { - - if (filesize>=BLOCK_SIZE) { - toread=BLOCK_SIZE; - } else { - toread=filesize; - } - - if (memory) - { - memcpy(block, memory+(fsize-filesize), toread); - } else { - if (read(fd, block, toread)!=toread) { - debug("error reading file data\n"); - close(fd); - MPIO_ERR_RETURN(MPIO_ERR_READING_FILE); - } - } - filesize -= toread; - - /* get new free block from FAT and write current block out */ - memcpy(¤t, f, sizeof(mpio_fatentry_t)); - if (!(mpio_fatentry_next_free(m, mem, f))) - { - debug ("Found no free cluster during mpio_file_put\n" - "This should never happen\n"); - exit(-1); - } - mpio_fatentry_set_next(m ,mem, ¤t, f); - mpio_io_block_write(m, mem, ¤t, block); - - if (progress_callback) - abort=(*progress_callback)((fsize-filesize), fsize); - } - - /* handle the last block to write */ - - if (filesize>=BLOCK_SIZE) { - toread=BLOCK_SIZE; - } else { - toread=filesize; - } - - if (memory) - { - memcpy(block, memory+(fsize-filesize), toread); - } else { - if (read(fd, block, toread)!=toread) { - debug("error reading file data\n"); - close(fd); - MPIO_ERR_RETURN(MPIO_ERR_READING_FILE); - } - } - filesize -= toread; - - /* mark end of FAT chain and write last block */ - mpio_fatentry_set_eof(m ,mem, f); - mpio_io_block_write(m, mem, f, block); - - if (!memory) - close(fd); - - if (progress_callback) - (*progress_callback)((fsize-filesize), fsize); - - if (abort) - { /* delete the just written blocks, because the user - * aborted the operation - */ - debug("aborting operation\n"); - debug("removing already written blocks\n"); - - filesize=fsize; - - memcpy(¤t, &firstblock, sizeof(mpio_fatentry_t)); - memcpy(&backup, &firstblock, sizeof(mpio_fatentry_t)); - - while (mpio_fatentry_next_entry(m, mem, ¤t)) - { - mpio_io_block_delete(m, mem, &backup); - mpio_fatentry_set_free(m, mem, &backup); - memcpy(&backup, ¤t, sizeof(mpio_fatentry_t)); - - if (filesize > BLOCK_SIZE) - { - filesize -= BLOCK_SIZE; - } else { - filesize -= filesize; - } - - if (progress_callback) - (*progress_callback)((fsize-filesize), fsize); - } - mpio_io_block_delete(m, mem, &backup); - mpio_fatentry_set_free(m, mem, &backup); - - if (filesize > BLOCK_SIZE) - { - filesize -= BLOCK_SIZE; - } else { - filesize -= filesize; - } - - if (progress_callback) - (*progress_callback)((fsize-filesize), fsize); - - } else { - if (memory) - { - time(&curr); - tt = * localtime(&curr); - } - mpio_dentry_put(m, mem, - o_filename, strlen(o_filename), - ((memory)?mktime(&tt):file_stat.st_ctime), - fsize, start, 0x20); - } - - mpio_id3_end(m); - - return fsize-filesize; -} - -int -mpio_file_switch(mpio_t *m, mpio_mem_t mem, - mpio_filename_t file1, mpio_filename_t file2) -{ - BYTE *p1, *p2; - - /* find files */ - p1 = mpio_dentry_find_name(m, mem, file1); - if (!p1) - p1 = mpio_dentry_find_name_8_3(m, mem, file1); - - p2 = mpio_dentry_find_name(m, mem, file2); - if (!p2) - p2 = mpio_dentry_find_name_8_3(m, mem, file2); - - if ((!p1) || (!p2)) - MPIO_ERR_RETURN(MPIO_ERR_FILE_NOT_FOUND); - - mpio_dentry_switch(m, mem, p1, p2); - - return 0; -} - -int -mpio_file_rename(mpio_t *m, mpio_mem_t mem, - mpio_filename_t old, mpio_filename_t new) -{ - BYTE *p; - - /* find files */ - p = mpio_dentry_find_name(m, mem, old); - if (!p) - p = mpio_dentry_find_name_8_3(m, mem, old); - - if (!p) - MPIO_ERR_RETURN(MPIO_ERR_FILE_NOT_FOUND); - - mpio_dentry_rename(m, mem, p, new); - - return 0; -} - -int mpio_file_move(mpio_t *m,mpio_mem_t mem, mpio_filename_t file, - mpio_filename_t after) -{ - BYTE *p1,*p2; - - if( ( p1 = mpio_dentry_find_name(m,mem,file)) == NULL ) { - if( (p1 = mpio_dentry_find_name_8_3(m, mem, file)) == NULL ) { - MPIO_ERR_RETURN(MPIO_ERR_FILE_NOT_FOUND); - } - } - - if(after!=NULL) { - if( ( p2 = mpio_dentry_find_name(m,mem,after)) == NULL ) { - if( (p2 = mpio_dentry_find_name_8_3(m, mem, after)) == NULL ) { - MPIO_ERR_RETURN(MPIO_ERR_FILE_NOT_FOUND); - } - } - } - - fprintf(stderr," -- moving '%s' after '%s'\n",file,after); - - mpio_dentry_move(m,mem,p1,p2); - - return 0; -} - -int -mpio_memory_format(mpio_t *m, mpio_mem_t mem, - mpio_callback_t progress_callback) -{ - int data_offset; - mpio_smartmedia_t *sm; - mpio_fatentry_t *f; - DWORD clusters; - BYTE abort = 0; - BYTE *cis, *mbr, *pbr; - BYTE defect[SECTOR_SIZE]; - int i; - - if (mem == MPIO_INTERNAL_MEM) - { - sm=&m->internal; - data_offset = 0x01; - } - - if (mem == MPIO_EXTERNAL_MEM) - { - sm = &m->external; - data_offset = 0x02; - } - - clusters = sm->size*128; - - - /* TODO: read and write "Config.dat" so the player does not become "dumb" */ - if (mem==MPIO_INTERNAL_MEM) - { - /* clear the fat before anything else, so we can mark clusters defective - * if we found a bad block - */ - /* external mem must be handled diffrently, - * see comment(s) below! - */ - mpio_fat_clear(m, mem); - f = mpio_fatentry_new(m, mem, data_offset, FTYPE_MUSIC); - do - { - - if (!mpio_io_block_delete(m, mem, f)) - mpio_fatentry_set_defect(m, mem, f); - - if (progress_callback) - { - if (!abort) - { - abort=(*progress_callback)(f->entry, sm->max_cluster + 1); - if (abort) - debug("received abort signal, but ignoring it!\n"); - } else { - (*progress_callback)(f->entry, sm->max_cluster + 1); - } - } - - } while (mpio_fatentry_plus_plus(f)); - free(f); - } - - if (mem == MPIO_EXTERNAL_MEM) { - /* delete all blocks! */ - - i=0; - while (i < sm->max_blocks) - { - mpio_io_block_delete_phys(m, mem, (i * BLOCK_SECTORS)); - i++; - - if (progress_callback) - { - if (!abort) - { - abort=(*progress_callback)(i, sm->max_blocks); - if (abort) - debug("received abort signal, but ignoring it!\n"); - } else { - (*progress_callback)(i, sm->max_blocks); - } - } - - - } - - /* generate "defect" first block */ - mpio_io_sector_write(m, mem, MPIO_BLOCK_DEFECT, defect); - - /* format CIS area */ - f = mpio_fatentry_new(m, mem, MPIO_BLOCK_CIS, FTYPE_MUSIC); - /* mpio_io_block_delete(m, mem, f); */ - free(f); - cis = (BYTE *)mpio_cis_gen(); /* hmm, why this cast? */ - mpio_io_sector_write(m, mem, MPIO_BLOCK_CIS, cis); - mpio_io_sector_write(m, mem, MPIO_BLOCK_CIS+1, cis); - free(cis); - - /* generate boot blocks ... */ - mbr = (BYTE *)mpio_mbr_gen(m->external.size); - pbr = (BYTE *)mpio_pbr_gen(m->external.size); - /* ... copy the blocks to internal memory structurs ... */ - memcpy(sm->cis, cis, SECTOR_SIZE); - memcpy(sm->mbr, mbr, SECTOR_SIZE); - memcpy(sm->pbr, pbr, SECTOR_SIZE); - /* ... and set internal administration accordingly */ - mpio_mbr_eval(sm); - mpio_pbr_eval(sm); - - if (!sm->fat) /* perhaps we have to build a new FAT */ - sm->fat=malloc(sm->fat_size*SECTOR_SIZE); - mpio_fat_clear(m, mem); - - /* TODO: for external memory we have to work a little "magic" - * to identify and mark "bad blocks" (because we have a set of - * spare ones! - */ - } - - mpio_rootdir_clear(m, mem); - - /* this writes the FAT *and* the root directory */ - mpio_fat_write(m, mem); - - if (progress_callback) - (*progress_callback)(sm->max_cluster+1, sm->max_cluster+1); - - return 0; -} - -int -mpio_file_del(mpio_t *m, mpio_mem_t mem, mpio_filename_t filename, - mpio_callback_t progress_callback) -{ - BYTE *p; - mpio_smartmedia_t *sm; - mpio_fatentry_t *f, backup; - DWORD filesize, fsize; - BYTE abort=0; - - MPIO_CHECK_FILENAME(filename); - - if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; - if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; - - if ((strcmp(filename, "..") == 0) || - (strcmp(filename, ".") == 0)) - { - debugn(2, "directory name not allowed: %s\n", filename); - MPIO_ERR_RETURN(MPIO_ERR_DIR_NAME_ERROR); - } - - /* find file */ - p = mpio_dentry_find_name(m, mem, filename); - if (!p) - p = mpio_dentry_find_name_8_3(m, mem, filename); - - if (p) - f = mpio_dentry_get_startcluster(m, mem, p); - - if (f && p) { - if (mpio_dentry_is_dir(m, mem, p) == MPIO_OK) - { - /* ugly */ - mpio_directory_cd(m, mem, filename); - if (mpio_directory_is_empty(m, mem, sm->cdir) != MPIO_OK) - { - mpio_directory_cd(m, mem, ".."); - MPIO_ERR_RETURN(MPIO_ERR_DIR_NOT_EMPTY); - } else { - mpio_directory_cd(m, mem, ".."); - } - } - - filesize=fsize=mpio_dentry_get_filesize(m, mem, p); - do - { - debugn(2, "sector: %4x\n", f->entry); - - mpio_io_block_delete(m, mem, f); - - if (filesize != fsize) - mpio_fatentry_set_free(m, mem, &backup); - - memcpy(&backup, f, sizeof(mpio_fatentry_t)); - - if (filesize > BLOCK_SIZE) - { - filesize -= BLOCK_SIZE; - } else { - filesize -= filesize; - } - - if (progress_callback) - { - if (!abort) - { - abort=(*progress_callback)((fsize-filesize), fsize); - if (abort) - debug("received abort signal, but ignoring it!\n"); - } else { - (*progress_callback)((fsize-filesize), fsize); - } - } - - } while (mpio_fatentry_next_entry(m, mem, f)); -/* mpio_io_block_delete(m, mem, &backup); */ - mpio_fatentry_set_free(m, mem, &backup); - free(f); - - } else { - debugn(2, "unable to locate the file: %s\n", filename); - MPIO_ERR_RETURN(MPIO_ERR_FILE_NOT_FOUND); - } - - mpio_dentry_delete(m, mem, filename); - - return MPIO_OK; -} - -int -mpio_sync(mpio_t *m, mpio_mem_t mem) -{ - mpio_smartmedia_t *sm; - - if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; - if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; - - if (!sm->size) - return 0; - - /* this writes the FAT *and* the root directory */ - return mpio_fat_write(m, mem); -} - -int -mpio_health(mpio_t *m, mpio_mem_t mem, mpio_health_t *r) -{ - mpio_smartmedia_t *sm; - int i, j, zones; - mpio_fatentry_t *f; - - if (mem == MPIO_INTERNAL_MEM) - { - sm = &m->internal; - r->num = sm->chips; - - f = mpio_fatentry_new(m, mem, 0x00, FTYPE_MUSIC); - - for (i=0 ; i < sm->chips; i++) - { - r->data[i].spare = 0; - r->data[i].total = (sm->max_cluster / sm->chips); - r->data[i].broken = 0; - /* now count the broken blocks */ - for(j=0; jdata[i].total; j++) - { - if (mpio_fatentry_is_defect(m, mem, f)) - r->data[i].broken++; - mpio_fatentry_plus_plus(f); - } - } - - free(f); - - return MPIO_OK; - } - - - if (mem == MPIO_EXTERNAL_MEM) - { - sm = &m->external; - - zones = sm->max_cluster / MPIO_ZONE_LBLOCKS + 1; - r->num = zones; - - for(i=0; idata[i].spare = (i?24:22); /* first zone has only 23 due to CIS */ - r->data[i].total = MPIO_ZONE_PBLOCKS; - r->data[i].broken = 0; - /* now count the broken blocks */ - for(j=0; jzonetable[i][j] == MPIO_BLOCK_DEFECT) - r->data[i].broken++; - } - if (r->data[i].spare < r->data[i].broken) - debug("(spare blocks expect trouble!\n"); - } - return MPIO_OK; - } - - return MPIO_ERR_INTERNAL; -} - -int -mpio_memory_dump(mpio_t *m, mpio_mem_t mem) -{ - BYTE block[BLOCK_SIZE]; - int i; - - if (mem == MPIO_INTERNAL_MEM) - { - hexdump(m->internal.fat, m->internal.max_blocks*0x10); - hexdump(m->internal.root->dir, DIR_SIZE); - } - - if (mem == MPIO_EXTERNAL_MEM) - { - hexdump(m->external.spare, m->external.max_blocks*0x10); - hexdump(m->external.fat, m->external.fat_size*SECTOR_SIZE); - hexdump(m->external.root->dir, DIR_SIZE); - } - - for (i = 0 ; i<=0x100 ; i++) - mpio_io_sector_read(m, mem, i, block); - - return 0; -} - -int -mpio_errno(void) -{ - int no = _mpio_errno; - _mpio_errno = 0; - - return no; -} - -char * -mpio_strerror(int err) -{ - int i; - - if (err >= 0) return NULL; - - for (i = 0; i < mpio_error_num; i++) { - if (mpio_errors[i].id == err) - return mpio_errors[i].msg; - } - - return NULL; -} - -void -mpio_perror(char *prefix) -{ - char *msg = mpio_strerror(_mpio_errno); - - if (msg == NULL) return; - - if (prefix) - fprintf(stderr, "%s: %s\n", prefix, msg); - else - fprintf(stderr, "%s\n", msg); -} diff --git a/libmpio/mpio.h b/libmpio/mpio.h deleted file mode 100644 index 5684b3d..0000000 --- a/libmpio/mpio.h +++ /dev/null @@ -1,218 +0,0 @@ -#/* -*- linux-c -*- */ - -/* - * $Id: mpio.h,v 1.18 2003/04/19 23:58:02 germeier Exp $ - * - * Library for USB MPIO-* - * - * Markus Germeier (mager@tzi.de) - * - * uses code from mpio_stat.c by - * Yuji Touya (salmoon@users.sourceforge.net) - * - * - * 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. - * - * */ - -#ifndef _MPIO_H_ -#define _MPIO_H_ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "defs.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* - *init and shutdown - */ - -mpio_t *mpio_init(mpio_callback_init_t); -void mpio_close(mpio_t *); - -/* - * request information - */ - -/* get version */ -void mpio_get_info(mpio_t *, mpio_info_t *); -/* get model */ -mpio_model_t mpio_get_model(mpio_t *); -/* retrieves free memory in bytes */ -int mpio_memory_free(mpio_t *, mpio_mem_t, int *free); - -/* - * charset for filename encoding/converting - */ -BYTE *mpio_charset_get(mpio_t *); -BYTE mpio_charset_set(mpio_t *, BYTE *); - -/* - * directory operations - */ - -/* context, memory bank */ -BYTE* mpio_directory_open(mpio_t *, mpio_mem_t); -/* context, memory bank, directory name */ -int mpio_directory_make(mpio_t *, mpio_mem_t, BYTE *); -/* context, memory bank, directory name */ -int mpio_directory_cd(mpio_t *, mpio_mem_t, BYTE *); -/* context, memory bank, directory name buffer space */ -void mpio_directory_pwd(mpio_t *, mpio_mem_t, BYTE pwd[INFO_LINE]); -/* context, dir context */ -BYTE* mpio_dentry_next(mpio_t *, mpio_mem_t, BYTE *); -/* context, dir context */ -int mpio_dentry_get(mpio_t *, mpio_mem_t, BYTE *, BYTE *, int,WORD *, - BYTE *, BYTE *, BYTE *, BYTE *, DWORD *, BYTE *); - -/* - * reading/writing/deleting of files - */ - -int mpio_file_get_as(mpio_t *, mpio_mem_t, mpio_filename_t, - mpio_filename_t,mpio_callback_t); - -/* context, memory bank, filename, callback */ -int mpio_file_get(mpio_t *, mpio_mem_t, mpio_filename_t, mpio_callback_t); - -/* context, memory bank, filename, filetype, callback */ -int mpio_file_put(mpio_t *, mpio_mem_t, mpio_filename_t, mpio_filetype_t, - mpio_callback_t); - -/* context, memory bank, filename, as, filetype, callback */ -int mpio_file_put_as(mpio_t *, mpio_mem_t, mpio_filename_t, - mpio_filename_t, mpio_filetype_t, - mpio_callback_t); - -/* context, memory bank, filename, callback */ -int mpio_file_del(mpio_t *, mpio_mem_t, mpio_filename_t, mpio_callback_t); - -/* - * reading/writing files into memory (used for config+font files) - */ - -/* context, memory bank, filename, callback, pointer to memory */ -/* the needed memory is allocated and the memory pointer is return */ -/* via the "BYTE **" */ - -int mpio_file_get_to_memory(mpio_t *, mpio_mem_t, mpio_filename_t, - mpio_callback_t, BYTE **); - -/* context, memory bank, filename, filetype, callback ... */ -/* ... memory pointer, size of file */ -int mpio_file_put_from_memory(mpio_t *, mpio_mem_t, mpio_filename_t, - mpio_filetype_t, mpio_callback_t, - BYTE *, int); - -/* - * rename a file on the MPIO - */ -/* context, memory bank, filename, filename */ -int mpio_file_rename(mpio_t *, mpio_mem_t, - mpio_filename_t, mpio_filename_t); - -/* - * switch position of two files - */ -/* context, memory bank, filename, filename */ -int mpio_file_switch(mpio_t *, mpio_mem_t, - mpio_filename_t, mpio_filename_t); - -/* Move a named file after a given file. If after==NULL move it - to the top of the list, -*/ - -int mpio_file_move(mpio_t *,mpio_mem_t m,mpio_filename_t,mpio_filename_t); - -/* - * formating a memory (internal mem or external SmartMedia card) - */ - -/* context, memory bank, callback */ -int mpio_memory_format(mpio_t *, mpio_mem_t, mpio_callback_t); - -/* mpio_sync has to be called after every set of mpio_file_{del,put} - * operations to write the current state of FAT and (root) directory. - * This is done explicitly to avoid writing these informations to often - * and thereby exhausting the SmartMedia chips - */ -/* context, memory bank */ -int mpio_sync(mpio_t *, mpio_mem_t); - -/* - * ID3 rewriting support - */ - -/* enable disable ID3 rewriting support */ -BYTE mpio_id3_set(mpio_t *, BYTE); -/* query ID3 rewriting support */ -BYTE mpio_id3_get(mpio_t *); - -/* set format string for rewriting*/ -void mpio_id3_format_set(mpio_t *, BYTE *); -/* get format string for rewriting*/ -void mpio_id3_format_get(mpio_t *, BYTE *); - -/* - * "special" functions - */ - -/* returns health status of selected memory */ -int mpio_health(mpio_t *, mpio_mem_t, mpio_health_t *); - -/* - * error handling - */ - -/* returns error code of last error */ -int mpio_errno(void); - -/* returns the description of the error */ -char * mpio_strerror(int err); - -/* prints the error message of the last error*/ -void mpio_perror(char *prefix); - -/* - * debugging - */ - -/* context, memory bank */ -int mpio_memory_dump(mpio_t *, mpio_mem_t); - -/* - * timeline: - * --------- - * 2004: some functions to change the order of files - * 2005: read mp3 tags of the files - */ - -#ifdef __cplusplus -} -#endif - -#endif /* _MPIO_H_ */ - - diff --git a/libmpio/mplib/mplib.c b/libmpio/mplib/mplib.c new file mode 100644 index 0000000..afa7066 --- /dev/null +++ b/libmpio/mplib/mplib.c @@ -0,0 +1,1011 @@ +/* + * mplib - a library that enables you to edit ID3 tags + * Copyright (C) 2001,2002 Stefan Podkowinski + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library 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 + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#if STDC_HEADERS +# include +# include +#elif HAVE_STRINGS_H +# include +#endif /*STDC_HEADERS*/ + +#if HAVE_UNISTD_H +# include +# include +#endif + +#include +#include +#include + +#include "xmalloc.h" +#include "mplib.h" +#include "mplib_s.h" +#include "mplib_s.c" + + + +/******************************************************************************************* + * Extern functions + *******************************************************************************************/ + + + +/******************************************************************************************* + * Get + *******************************************************************************************/ + + mpeg_header* + mp_get_mpeg_header_from_file(const char* filename) + { + mpeg_header *ret; + int fd; + + if(!filename) return NULL; + + fd = open(filename, O_RDONLY); + if(fd == -1) return NULL; + + ret = mp_get_mpeg_header_from_fd(fd); + close(fd); + return ret; + } + + +mpeg_header* +mp_get_mpeg_header_from_fd(int fd) +{ + mpeg_header *h; + unsigned char c[5]; + + h = XMALLOCD(mpeg_header, "mp_get_mpeg_header_from_fd:h"); + + if(id3_lseek_syncword(fd)) goto exit_on_error; + + if(read(fd, c, 4) < 4) goto exit_on_error; + + memset(h, 0, sizeof(h)); + h->syncword = (c[1] & 240); + h->syncword <<= 8; + h->syncword |= c[0]; + h->version = (c[1] & 8) >> 3; + h->layer = (c[1] & 6) >> 1; + h->protbit = (c[1] & 1); + h->bitrate = (c[2] & 240) >> 4; + h->samplingfreq = (c[2] & 12) >> 2; + h->padbit = (c[2] & 2) >> 1; + h->privbit = (c[2] & 1); + h->mode = (c[3] & 192) >> 6; + h->mode_ext = (c[3] & 48) >> 4; + h->copyright = (c[3] & 8) >> 3; + h->originalhome = (c[3] & 4) >> 2; + h->emphasis = (c[3] & 3); + + return h; + + exit_on_error: + xfree(h); + return NULL; +} + +char* +mp_get_str_version(const mpeg_header *h) +{ + return h->version == 0 ? "MPEG 2" : "MPEG 1"; +} + +char* +mp_get_str_layer(const mpeg_header *h) +{ + switch(h->layer) + { + case 1: return "Layer III"; + case 2: return "Layer II"; + case 3: return "Layer I"; + default: return "undefined"; + } +} + +char* +mp_get_str_bitrate(const mpeg_header *h) +{ + char *buf = (char *)xmallocd0(11, "mp_get_str_bitrate:buf"); + + if(h->version == 1) /* MPEG 1 */ + { + switch(h->layer) + { + case 1: + snprintf(buf, sizeof buf, "%d kBit/s", br_1_3[h->bitrate]); + return buf; + case 2: + snprintf(buf, sizeof buf, "%d kBit/s", br_1_2[h->bitrate]); + return buf; + case 3: + snprintf(buf, sizeof buf, "%d kBit/s", br_1_1[h->bitrate]); + return buf; + default: + return "undefined"; + } + } + else /* MPEG 2 */ + { + switch(h->layer) + { + case 1: + snprintf(buf, sizeof buf, "%d kBit/s", br_2_3[h->bitrate]); + return buf; + case 2: + snprintf(buf, sizeof buf, "%d kBit/s", br_2_2[h->bitrate]); + return buf; + case 3: + snprintf(buf, sizeof buf, "%d kBit/s", br_2_1[h->bitrate]); + return buf; + default: + return "undefined"; + } + } +} + +char* +mp_get_str_samplingfreq(const mpeg_header *h) +{ + if(h->version == 1) + { + switch(h->samplingfreq) + { + case 0: return "44100 Hz"; + case 1: return "48000 Hz"; + case 2: return "32000 Hz"; + default: return "undefined"; + } + } + else + { + switch(h->samplingfreq) + { + case 0: return "22050 Hz"; + case 1: return "24000 Hz"; + case 2: return "16000 Hz"; + default: return "undefined"; + } + } +} + +char* +mp_get_str_mode(const mpeg_header *h) +{ + switch(h->mode) + { + case 0: return "Stereo"; + case 1: return "Joint-Stereo"; + case 2: return "Dual-Channel"; + case 3: return "Mono"; + default: return "undefined"; + } +} + +id3_tag_list* +mp_get_tag_list_from_file(const char* filename) +{ + id3_tag_list *ret; + int fd; + + if(!filename) return NULL; + + fd = open(filename, O_RDONLY); + if(fd == -1) return NULL; + + ret = mp_get_tag_list_from_fd(fd); + close(fd); + return ret; +} + +id3_tag_list* +mp_get_tag_list_from_fd(int fd) +{ + id3_tag_list *tag_list = NULL; + id3_tag_list *tag_list2 = NULL; + id3v2_tag *v2tag = NULL; + id3v1_tag *v1tag = NULL; + id3_tag *tag = NULL; + + v2tag = id3v2_get_tag(fd); + if(v2tag) + { + tag = XMALLOCD0(id3_tag, "mp_get_tag_list_from_fd:tag"); + if(v2tag->header->version_minor == 3 || v2tag->header->version_minor == 4) + tag->version = 2; + else + tag->version = -1; + tag->tag = v2tag; + + tag_list = XMALLOCD(id3_tag_list, "mp_get_tag_list_from_fd:tag_list"); + tag_list->tag = tag; + tag_list->next = NULL; + tag_list->first = tag_list; + } + + v1tag = id3v1_get_tag(fd); + if(v1tag) + { + tag = XMALLOCD(id3_tag, "mp_get_tag_list_from_fd:tag"); + tag->version = 1; + tag->tag = v1tag; + + if(tag_list) + { + tag_list2 = XMALLOCD(id3_tag_list, "mp_get_tag_list_from_fd:tag_list2"); + tag_list2->tag = tag; + tag_list2->next = NULL; + tag_list2->first = tag_list; + tag_list->next = tag_list2; + } + else + { + tag_list = XMALLOCD(id3_tag_list, "mp_get_tag_list_from_fd:tag_list"); + tag_list->tag = tag; + tag_list->next = NULL; + tag_list->first = tag_list; + } + } + + return tag_list; +} + +id3_content* +mp_get_content(const id3_tag *tag, int field) +{ + return mp_get_content_at_pos(tag, field, 0); +} + +id3_content* +mp_get_content_at_pos(const id3_tag *tag, int field, int pos) +{ + int i; + char *c; + id3_content *ret; + + if(!tag || !tag->tag) + { + errno = MP_EERROR; + return NULL; + } + + if(tag->version == 1) + { + if(pos != 0) + { + errno = MP_EERROR; + return NULL; + } + else return id3v1_get_content(tag->tag, field); + } + else if(tag->version == 2) + { + id3v2_tag *v2 = tag->tag; + char *val; + + switch(field) + { + case MP_ARTIST: + return mp_get_content_custom_at_pos(tag, "TPE1", pos); + case MP_TITLE: + return mp_get_content_custom_at_pos(tag, "TIT2", pos); + case MP_ALBUM: + return mp_get_content_custom_at_pos(tag, "TALB", pos); + case MP_GENRE: + return mp_get_content_custom_at_pos(tag, "TCON", pos); + case MP_COMMENT: + return mp_get_content_custom_at_pos(tag, "COMM", pos); + case MP_YEAR: + return mp_get_content_custom_at_pos(tag, "TYER", pos); + case MP_TRACK: + return mp_get_content_custom_at_pos(tag, "TRCK", pos); + } + errno = MP_EFNF; + return NULL; + } + else + { + errno = MP_EVERSION; + return NULL; + } +} + +id3_content* +mp_get_content_custom(const id3_tag* tag, const char*field) +{ + if(!tag) + { + errno = MP_EERROR; + return NULL; + } + else if(tag->version != 2) + { + errno = MP_EVERSION; + return NULL; + } + + return id3v2_get_content_at_pos(tag->tag, field, 0); + +} + +id3_content* +mp_get_content_custom_at_pos(const id3_tag* tag, const char*field, int pos) +{ + if(!tag) + { + errno = MP_EERROR; + return NULL; + } + else if(tag->version != 2) + { + errno = MP_EVERSION; + return NULL; + } + + + return id3v2_get_content_at_pos(tag->tag, field, pos); +} + + +/******************************************************************************************* + * Set + *******************************************************************************************/ + + int + mp_set_content(id3_tag* tag, const int field, id3_content* new_content) + { + id3v1_tag *v1; + id3v2_tag *v2; + + + if(!tag) return MP_EERROR; + + if(tag->version == 2) + { + return mp_set_content_at_pos(tag, field, new_content, 0); + } + else if(tag->version == 1) + { + unsigned char c; + char *my_val; + int len, j; + + v1 = tag->tag; + + switch(field) + { + +#define FLD(str1, str2, str3, str4) \ + case str1:\ + if(!new_content) v1->str2 = NULL;\ + else\ + {\ + id3_text_content *tc = str4(new_content);\ + if(strlen(tc->text) > str3 || tc->encoding != ISO_8859_1)\ + {\ + mp_convert_to_v2(tag);\ + mp_free_text_content(tc);\ + return mp_set_content(tag, field, new_content);\ + }\ + \ + v1->str2 = tc->text;\ + xfree(tc);\ + }\ + break; + + FLD(MP_ARTIST, artist, 30, mp_parse_artist); + FLD(MP_TITLE, title, 30, mp_parse_title); + FLD(MP_ALBUM, album, 30, mp_parse_album); + FLD(MP_YEAR, year, 4, mp_parse_year); + + case MP_COMMENT: + if(!new_content) v1->comment = NULL; + else + { + id3_comment_content *tc = mp_parse_comment(new_content); + if(strlen(tc->text) > 30 || tc->short_descr || tc->encoding != ISO_8859_1) + { + mp_convert_to_v2(tag); + mp_free_comment_content(tc); + return mp_set_content(tag, field, new_content); + } + v1->comment = xmallocd0(strlen(tc->text)+1, + "mp_set_content:v1->comment"); + memcpy(v1->comment, tc->text, strlen(tc->text)); + mp_free_comment_content(tc); + } + break; + + case MP_TRACK: + if(!new_content) v1->track = 0; + else + { + id3_text_content *tc = mp_parse_track(new_content); +#ifdef HAVE_STRTOL + errno = 0; + j = strtol(tc->text, (char **)NULL, 10); + if(errno != ERANGE) v1->track = j; + else return MP_EERROR; +#else + v1->track = atoi(tc->text); +#endif + mp_free_text_content(tc); + } + break; + + case MP_GENRE: + if(!new_content) v1->genre = 0xFF; + else + { + int b = 0, i; + id3_text_content *tc = mp_parse_genre(new_content); + /* i = strlen(tc->text); */ + for(c = 0; c < GLL; c++) { + if(!strcmp(genre_list[c], tc->text)) + { + v1->genre = c; + b = 1; + } + } + mp_free_text_content(tc); + if(!b) + { + mp_convert_to_v2(tag); + return mp_set_content(tag, field, new_content); + } + break; + } + } + } + else if(tag->version == -1) return MP_EVERSION; + else return MP_EFNF; + + return 0; + } + +int +mp_set_content_at_pos(id3_tag* tag, const int field, id3_content* new_content, int pos) +{ + char* c; + + if(!tag) return MP_EERROR; + if(field < MP_ARTIST || field > MP_TRACK) return MP_EFNF; + + if(tag->version == 1 && pos == 0) return mp_set_content(tag, field, new_content); + + switch(field) + { + case MP_ARTIST: c = "TPE1"; break; + case MP_TITLE: c = "TIT2"; break; + case MP_ALBUM: c = "TALB"; break; + case MP_TRACK: c = "TRCK"; break; + case MP_YEAR: c = "TYER"; break; + case MP_COMMENT: c = "COMM"; break; + case MP_GENRE: c = "TCON"; break; + } + return mp_set_custom_content_at_pos(tag, c, new_content, pos); +} + +int +mp_set_custom_content(id3_tag* tag, char* field, id3_content* new_content) +{ + return mp_set_custom_content_at_pos(tag, field, new_content, 0); +} + +int +mp_set_custom_content_at_pos(id3_tag* tag, char* field, id3_content* new_content, int pos) +{ + id3v2_tag *v2; + + if(!tag || !field || strlen(field) != 4) return MP_EERROR; + + if(tag->version == 1) + { + if(mp_convert_to_v2(tag)) + return MP_EERROR; + } + else if(tag->version == -1) return MP_EVERSION; + + v2 = (id3v2_tag*)tag->tag; + if(!v2->frame_list) + { + v2->frame_list = XMALLOCD0(id3v2_frame_list, + "mp_set_custom_content_at_pos:v2->frame_list"); + id3_add_frame(v2->frame_list, field, new_content->data, new_content->length); + } + else + { + id3v2_frame *frame; + + if((frame = id3_lookup_frame(v2->frame_list, field, pos))) + { + if(new_content) + { + long len, len_sync; + /* make sync safe */ + len = new_content->length; + len_sync = id3_sync(new_content->data, len); + + xfree(frame->data); + frame->data = xmallocd(new_content->length, + "mp_set_custom_content_at_pos:frame->data"); + memcpy(frame->data, new_content->data, new_content->length); + frame->status_flag = 0; + if(len != len_sync) frame->format_flag = 64; + else frame->format_flag = 0; + frame->data_size = len_sync; + } + else id3_remove_frame(v2->frame_list, frame); + } + else if(pos == 0) id3_add_frame(v2->frame_list, field, new_content->data, new_content->length); + else return MP_EFNF; + } + + return 0; +} + +/******************************************************************************************* + * Write & delete + *******************************************************************************************/ + int + mp_write_to_file(const id3_tag_list* tag_list, const char *filename) + { + int ret; + int fd; + + if(!filename) return MP_EERROR; + + fd = open(filename, O_RDWR); + if(fd == -1) return MP_EERROR; + + ret = mp_write_to_fd(tag_list, fd); + close(fd); + return ret; + } + + + int + mp_write_to_fd(const id3_tag_list* tag_list, const int fd) + { + id3_tag *tag; + id3v1_tag *v1; + id3v2_tag *v2; + id3_tag_list *mylist; + int ret = 0; + + if(!tag_list) { + ret |= id3v1_del_tag(fd); + ret |= id3v2_del_tag(fd, NULL); + return ret; + } + + while(tag_list) + { + tag = tag_list->tag; + if(!tag) + { + tag_list = tag_list->next; + continue; + } + + if(tag->version == 1) + { + id3v1_del_tag(fd); + ret |= id3v1_add_tag(fd, tag->tag); + } + else if(tag->version == 2) + { + int pad = 0; + id3v2_frame_list *frame_list; + id3v2_tag *old_v2; + id3v2_tag *v2 = tag->tag; + + /* calculate tag size */ + v2->header->total_tag_size = 10; + if(v2->header->has_footer) v2->header->total_tag_size += 10; + if(v2->header->has_extended_header) v2->header->total_tag_size += v2->header->extended_header->size; + frame_list = v2->frame_list; + while(frame_list) + { + v2->header->total_tag_size += frame_list->data->data_size + 10; + frame_list = frame_list->next; + } + + /* this is where padding handling takes place */ + /* we must get the old tag to see if padding can be used */ + old_v2 = id3v2_get_tag(fd); + if(old_v2) { + if(v2->header->total_tag_size > old_v2->header->total_tag_size) + { + /* padding not sufficent */ + ret |= id3v2_del_tag(fd, old_v2); + ret |= id3v2_add_tag(fd, v2, NULL); + } + else + { + ret |= id3v2_add_tag(fd, v2, old_v2); + } + id3v2_free_tag(old_v2); + } else { + ret |= id3v2_add_tag(fd, v2, NULL); + } + + } + else + { + ret |= MP_EVERSION; + } + + tag_list = tag_list->next; + } /* tag list */ + + return ret; + } + +int +mp_del_tags_from_file(const char* filename) +{ + int ret, fd; + + if(!filename) return 1; + + fd = open(filename, O_RDWR); + if(fd == -1) return 1; + + ret = mp_del_tags_from_fd(fd); + close(fd); + return ret; +} + +int +mp_del_tags_from_fd(const int fd) +{ + int ret = 0; + + ret |= id3v1_del_tag(fd); + ret |= id3v2_del_tag(fd, NULL); + + return ret; +} + +int +mp_del_tags_by_ver_from_file(const char* filename, const int version) +{ + int fd, ret; + + if(!filename) return 1; + + fd = open(filename, O_RDWR); + if(fd == -1) return 1; + + ret = mp_del_tags_by_ver_from_fd(fd, version); + close(fd); + return ret; +} + +int +mp_del_tags_by_ver_from_fd(const int fd, const int version) +{ + if(version == 1) return id3v1_del_tag(fd); + else if(version == 2) return id3v2_del_tag(fd, NULL); + else return MP_EVERSION; +} + + + + +/******************************************************************************************* + * Misc + *******************************************************************************************/ + + int + mp_convert_to_v2(id3_tag *tag) + { + id3v1_tag *v1; + id3_tag *tmp; + id3_content* content; + + if(tag->version == 2) return 0; + else if(tag->version == -1) return MP_EVERSION; + + tmp = mp_alloc_tag_with_version(2); + + v1 = (id3v1_tag*)tag->tag; + + content = mp_assemble_text_content(v1->artist, ISO_8859_1); + if(v1->artist) mp_set_content(tmp, MP_ARTIST, content); + + content = mp_assemble_text_content(v1->title, ISO_8859_1); + if(v1->title) mp_set_content(tmp, MP_TITLE, content); + + content = mp_assemble_text_content(v1->album, ISO_8859_1); + if(v1->album) mp_set_content(tmp, MP_ALBUM, content); + + content = mp_assemble_text_content(v1->year, ISO_8859_1); + if(v1->year) mp_set_content(tmp, MP_YEAR, content); + + content = mp_assemble_comment_content(v1->comment, NULL, ISO_8859_1, NULL); + if(v1->comment) mp_set_content(tmp, MP_COMMENT, content); + + if(v1->genre != 0xFF) + { + char *c = xmallocd(strlen(genre_list[v1->genre]) + 1, + "mp_convert_to_v2:c"); + strcpy(c, genre_list[v1->genre]); + content = mp_assemble_text_content(c, ISO_8859_1); + mp_set_content(tmp, MP_GENRE, content); + } + if(v1->track > 0) + { + char *trk = (char *)xmallocd(4, "mp_convert_to_v2:trk"); + snprintf(trk, 3, "%d", v1->track); + trk[3] = 0; + content = mp_assemble_text_content(trk, ISO_8859_1); + mp_set_content(tmp, MP_TRACK, content); + } + + tag->version = 2; + tag->tag = tmp->tag; + + id3v1_free_tag(v1); + xfree(tmp); + + return 0; + } + +int +mp_convert_to_v1(id3_tag *tag) +{ + id3v1_tag *v1; + id3_tag* tmp; + id3_content* content; + id3_text_content* tc; + id3_comment_content* cc; + char* c; + int j, k = 0; + + if(tag->version == 1) return 0; + else if(tag->version == -1) return MP_EVERSION; + + v1 = XMALLOCD0(id3v1_tag, "mp_convert_to_v1:v1"); + + content = mp_get_content(tag, MP_ARTIST); + tc = mp_parse_artist(content); + v1->artist = tc->text; + xfree(tc); + mp_free_content(content); + + content = mp_get_content(tag, MP_TITLE); + tc = mp_parse_title(content); + v1->title = tc->text; + xfree(tc); + mp_free_content(content); + + content = mp_get_content(tag, MP_ALBUM); + tc = mp_parse_album(content); + v1->album = tc->text; + xfree(tc); + mp_free_content(content); + + content = mp_get_content(tag, MP_YEAR); + tc = mp_parse_year(content); + v1->year = tc->text; + xfree(tc); + mp_free_content(content); + + content = mp_get_content(tag, MP_COMMENT); + cc = mp_parse_comment(content); + v1->comment = cc->text; + xfree(cc->language); + xfree(cc->short_descr); + xfree(cc); + mp_free_content(content); + + content = mp_get_content(tag, MP_TRACK); + tc = mp_parse_track(content); + c = tc->text; + if(c) + { +#ifdef HAVE_STRTOL + errno = 0; + j = strtol(c, (char **)NULL, 10); + if(errno != ERANGE) v1->track = j; + else v1->track = 0; +#else + v1->track = atoi(c); +#endif + } + else v1->track = 0; + xfree(c); + mp_free_text_content(tc); + mp_free_content(content); + + content = mp_get_content(tag, MP_GENRE); + tc = mp_parse_genre(content); + c = tc->text; + for(j = 0; c, j < GLL; j++) { + if(!strcmp(genre_list[j], c)) + { + v1->genre = j; + k = 1; + } + } + if(!c) v1->genre = 0xFF; + xfree(c); + mp_free_text_content(tc); + mp_free_content(content); + + id3v1_truncate_tag(v1); + + id3v2_free_tag(tag->tag); + + tag->version = 1; + tag->tag = v1; + + return 0; +} + +int +mp_is_valid_v1_value(int field, char *value) +{ + int len = 30; + int j; + + switch(field) { + case MP_YEAR: + len = 4; + break; + + case MP_TRACK: +#ifdef HAVE_STRTOL + errno = 0; + j = strtol(value, (char **)NULL, 10); + if(errno != ERANGE) return 1; + else return 0; +#else + return 1; /* poor fellow */ +#endif + + case MP_GENRE: + for(j = 0; j < GLL; j++) { + if(!strcmp(genre_list[j], value)) + { + return 1; + } + return 0; + } + } + + /* Check string length */ + if(strlen(value) > len) return 0; + else return 1; +} + + +void +mp_free_list(id3_tag_list *list) +{ + if(!list) return; + + /* free tag */ + if(list->tag) mp_free_tag(list->tag); + + /* free next element */ + if(list->next) mp_free_list(list->next); + + /* free this element */ + xfree(list); +} + +id3_tag* +mp_alloc_tag(void) +{ + /* The tags initialized version makes a different. Generally spoken, we + like to make id3v1 tags if possible and therefor set the version to 1 + here. This matters in mp_set_content(). */ + return mp_alloc_tag_with_version(1); +} + +id3_tag* +mp_alloc_tag_with_version(int v) +{ + id3_tag* ret; + + if(v != 1 && v != 2) return NULL; + + ret = XMALLOCD(id3_tag, "mp_alloc_tag_with_version:ret"); + ret->version = v; + if(v == 1) + { + ret->tag = XMALLOCD0(id3v1_tag, "mp_alloc_tag_with_version:ret->tag"); + ((id3v1_tag*)ret->tag)->genre = 0xFF; + } + else + { + id3v2_tag *v2; + /* XXX */ + ret->tag = XMALLOCD0(id3v2_tag, "mp_alloc_tag_with_version:ret->tag"); + v2 = (id3v2_tag*)ret->tag; + v2->header = XMALLOCD0(id3v2_header, "mp_alloc_tag_with_version:v2->header"); +//if ID3VERSION == "2.4" + v2->header->version_minor = 4; +//else + v2->header->version_minor = 3; +//endif + v2->header->version_revision = 0; + v2->header->unsyncronization = 1; + v2->header->has_extended_header = 0; + v2->header->is_experimental = 1; + v2->header->has_footer = 0; + v2->header->flags = 0; + v2->header->total_tag_size = 0; + v2->header->extended_header = NULL; + v2->frame_list = NULL; + } + return ret; +} + +void +mp_free_tag(id3_tag *tag) +{ + if(!tag) return; + + if(tag->version == 1) + { + id3v1_free_tag(tag->tag); + } + else if(tag->version == 2) + { + id3v2_free_tag(tag->tag); + } + xfree(tag); +} + +void +mp_free_content(id3_content *content) +{ + if(!content) return; + xfree(content->data); + xfree(content); +} + +void +mp_free_text_content(id3_text_content *content) +{ + if(!content) return; + xfree(content->text); + xfree(content); +} + +void +mp_free_comment_content(id3_comment_content *content) +{ + if(!content) return; + xfree(content->language); + xfree(content->short_descr); + xfree(content->text); + xfree(content); +} + + diff --git a/libmpio/mplib/mplib.h b/libmpio/mplib/mplib.h new file mode 100644 index 0000000..8b3fe64 --- /dev/null +++ b/libmpio/mplib/mplib.h @@ -0,0 +1,438 @@ +/* + * mplib - a library that enables you to edit ID3 tags + * Copyright (C) 2001,2002 Stefan Podkowinski + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library 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 + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __MPLIB_H +#define __MPLIB_H + + +/* __BEGIN_DECLS should be used at the beginning of your declarations, + so that C++ compilers don't mangle their names. Use __END_DECLS at + the end of C declarations. */ +#undef __BEGIN_DECLS +#undef __END_DECLS +#ifdef __cplusplus +# define __BEGIN_DECLS extern "C" { +# define __END_DECLS } +#else +# define __BEGIN_DECLS /* empty */ +# define __END_DECLS /* empty */ +#endif + +/* __P is a macro used to wrap function prototypes, so that compilers + that don't understand ANSI C prototypes still work, and ANSI C + compilers can issue warnings about type mismatches. */ +#undef __P +#if defined (__STDC__) || defined (_AIX) \ + || (defined (__mips) && defined (_SYSTYPE_SVR4)) \ + || defined(WIN32) || defined(__cplusplus) +# define __P(protos) protos +#else +# define __P(protos) () +#endif + + +__BEGIN_DECLS + + + +/*************************************/ +/* Defines */ +/*************************************/ + +#define MP_ARTIST 1 +#define MP_TITLE 2 +#define MP_ALBUM 3 +#define MP_GENRE 4 +#define MP_COMMENT 5 +#define MP_YEAR 6 +#define MP_TRACK 7 + +#define ISO_8859_1 0 +#define UTF16 1 +#define UTF16BE 2 +#define UTF8 3 + + +/*************************************/ +/* errno values */ +/*************************************/ +#define MP_EERROR 1 +#define MP_EFNF 2 +#define MP_EFCOMPR 3 +#define MP_EFENCR 4 +/*define MP_EUNICODE 5*/ +#define MP_EVERSION 6 + + +/*************************************/ +/* Structs and company */ +/*************************************/ + +/* Header structure with 4 segments containing 32 bit header information */ +typedef struct _mpeg_header +{ + unsigned int syncword; /* Sync Word */ + unsigned int version; /* Version number */ + unsigned int layer; /* Layer number */ + unsigned int protbit; /* Protection Bit */ + unsigned int bitrate; /* kbit/sec */ + unsigned int samplingfreq; /* hz */ + unsigned int padbit; /* Padding bit */ + unsigned int privbit; /* Private Bit */ + unsigned int mode; /* Stereo, Joint-Stereo, Dual-Channel, Mono */ + unsigned int mode_ext; /* Mode extension */ + unsigned int copyright; /* Copyright yes/no */ + unsigned int originalhome; /* Original datastream yes/no */ + unsigned int emphasis; /* Emphasis bits */ +} mpeg_header; + + +/* Generic tag structure */ +typedef struct _id3_tag +{ + int version; /* tags version, either 1 or 2 or -1 if not supported */ + void *tag; /* pointer to specific struct */ +} id3_tag; + + +/* list of tags found in file */ +typedef struct _id3_tag_list +{ + id3_tag *tag; + struct _id3_tag_list *next; + struct _id3_tag_list *first; +} id3_tag_list; + + +/* + * The following structures are ment as low-level data holders. I strongly + * suggest you to use the appropriate generic functions below to access them. + */ + +/* V 1 */ + +/* ID3v1 tag structure */ +typedef struct _id3v1_tag +{ + char *title; + char *artist; + char *album; + char *year; + char *comment; + unsigned char track; /* track binary encoded */ + unsigned char genre; /* index on genre list - 0xFF for null */ +} id3v1_tag; + + +/* V 2 */ + +/* ID3v2 Frame structure */ +typedef struct _id3v2_frame +{ + char* frame_id; /* The frame id e.g. TALB */ + unsigned char status_flag; + unsigned char format_flag; + char *data; + unsigned int data_size; /* frame size excluding header, incl. enc.,lang.,etc. + (total frame size - 10) */ +} id3v2_frame; + +/* single linked list referencing a number of frames */ +typedef struct _id3v2_frame_list +{ + struct _id3v2_frame *data; + struct _id3v2_frame_list *next; + struct _id3v2_frame_list *start; +} id3v2_frame_list; + +/* ID3v2 Extended Header structure */ +typedef struct _id3v2_extended_header +{ + unsigned long size; + char *flag_bytes; + unsigned int no_flag_bytes; + unsigned int is_update; + unsigned int crc_data_present; + unsigned char crc_data_length; + unsigned char* crc_data; + unsigned int restrictions; + unsigned char restrictions_data_length; + unsigned char* restrictions_data; +} id3v2_extended_header; + +/* ID3v2 Header structure */ +typedef struct _id3v2_header +{ + /* Version 2.minor.revision */ + unsigned int version_minor; + unsigned int version_revision; + char flags; /* Flags - should only be set by mplib and does only contain + the following infos */ + unsigned int unsyncronization; + unsigned int has_extended_header; + unsigned int is_experimental; + unsigned int has_footer; + unsigned long total_tag_size; /* is size of all tag elements including + header and footer (each 10 bytes) */ + id3v2_extended_header *extended_header; /* Extended header */ +} id3v2_header; + + +/* ID3v2 tag structure */ +typedef struct _id3v2_tag +{ + id3v2_header *header; + id3v2_frame_list *frame_list; +} id3v2_tag; + +/* A fields content unparsed */ +typedef struct _id3_content +{ + unsigned int compressed; + unsigned int encrypted; + char *data; + unsigned int length; +} id3_content; + +typedef enum _id3_encoding +{ + iso_8859_1 = ISO_8859_1, + utf16 = UTF16, + utf16be = UTF16BE, + utf8 = UTF8 +} id3_encoding; + +typedef struct _id3_text_content +{ + id3_encoding encoding; + char *text; /* Null terminated text */ +} id3_text_content; + +typedef struct _id3_comment_content +{ + id3_encoding encoding; + char *language; /* ISO Language code */ + char *short_descr; /* Null term. content short description */ + char *text; /* Null terminated text */ +} id3_comment_content; + +/***************************************/ +/* Functions */ +/***************************************/ + +/* Allocates a MPEG header structure from a file + * Arg 1 - The filename + * Returns - A pointer to a new initialized header structure - NULL on IO Error + */ +extern mpeg_header *mp_get_mpeg_header_from_file __P((const char*)); + + +/* Gets the header structure from a file descriptor + * Arg 1 - The file descriptor + * Returns - A pointer to a new initialized header structure - NULL on IO Error + */ +extern mpeg_header *mp_get_mpeg_header_from_fd __P((int)); + + +/* Frees a mpeg header structure + * Arg 1 - The allocated mpeg header + */ +#define mp_free_mpeg_header(str) xfree(str) + + +/* Allocates a label with the appropriate header field value as a string */ +extern char *mp_get_str_version __P((const mpeg_header*)); +extern char *mp_get_str_layer __P((const mpeg_header*)); +extern char *mp_get_str_bitrate __P((const mpeg_header*)); +extern char *mp_get_str_samplingfreq __P((const mpeg_header*)); +extern char *mp_get_str_mode __P((const mpeg_header*)); + + +/* Allocates and fills a list of tags found in the given file. This list + * will contain at least one and at most two tags or is NULL if no tags + * have been found. + * Arg 1 - The files name/file descriptor to search for tags + * Returns - A pointer to a initialized list struct or null if no tags have + * been found + */ +extern id3_tag_list* mp_get_tag_list_from_file __P((const char*)); +extern id3_tag_list* mp_get_tag_list_from_fd __P((int)); + + +/* Frees a tag list beginning with the given element XXX */ +extern void mp_free_list __P((id3_tag_list*)); + + +/* Gets the first content found of a specified field in the given tag and + * allocates a struct. + * Arg 1 - The tag + * Arg 2 - The fields identifier + * + * Returns The new allocated content for the specified field or NULL + * On NULL: errno set to the following values + * MP_EERROR - General failure: may occure on wrong usage, but should never happen + * MP_EFNF - Field does not exists in tag /invalid identifier + * MP_EVERSION - Tag has a version set that is not supported by the library + */ +extern id3_content* mp_get_content __P((const id3_tag*, int)); + +/* It's posible that a tag has multiple ocurances of a field. + * Use this function to get a specified field by position. The first + * ocurance of the field in the tag is 0. + * e.g.: To get the third comment in an id3v2 tag use + * mp_get_content_at_pos(tag, MP_COMMENT, 2); + * Arg 1 - The tag + * Arg 2 - The fields identifier + * Arg 3 - The content position in the tag + * Returns - see mp_get_content + */ +extern id3_content* mp_get_content_at_pos __P((const id3_tag*, int, int)); + +/* Gets a custom fields content and allocates a struct. This function can + * only be applied to ID3v2 tags. It will lookup a by the given identifier + * and return its content. + * Arg 1 - The tag + * Arg 2 - The field names identifier e.g. ENCR + * Returns - see mp_get_content + */ +extern id3_content* mp_get_content_custom __P((const id3_tag*, const char*)); + +/* See mp_get_content_at_pos() and mp_get_content_custom() + * Arg 1 - The tag + * Arg 2 - The field names identifier e.g. ENCR + * Arg 3 - The content position in the tag + * Returns - see mp_get_content + */ +extern id3_content* mp_get_content_custom_at_pos __P((const id3_tag*, const char*, int)); + +/* Frees a content struct */ +extern void mp_free_content __P((id3_content*)); +extern void mp_free_text_content __P((id3_text_content*)); +extern void mp_free_comment_content __P((id3_comment_content*)); + + +/* Copys the value of a specified field into the given tag. The content + * argument may be freed after using this function. The way a content + * is represented in a tag depends from the tags version and kind of field. + * I.e. it may be nessecary to represent a track number as a binary value in a v1 + * tag or to embeded it into a frame for a v2 tag. The caller just needs to + * give the correct identifier with the value as a id3_content and to take + * care of freeing the id3_content value afterwards. + * Arg 1 - The tag to edit + * Arg 2 - The fields identifier + * Arg 3 - The fields new content + * Returns - 0 success or one of the following errors + * MP_EERROR - General failure: may occure on wrong usage, but should never happen + * MP_EFNF - Field does not exists in tag /invalid identifier + * MP_EVERSION - Function isn't able to handle a tag of this version + */ +extern int mp_set_content __P((id3_tag*, int, id3_content*)); +extern int mp_set_content_at_pos __P((id3_tag*, int, id3_content*, int)); + +/* Sets up a new custom field with the given value + * Arg 1 - The tag to edit + * Arg 2 - The new fields name - A four chars upper case identifier e.g. ENCR + * Arg 3 - The fields new content + * Returns - See mp_set_content + */ +extern int mp_set_custom_content __P((id3_tag*, char*, id3_content*)); +extern int mp_set_custom_content_at_pos __P((id3_tag*, char*, id3_content*, int)); + +/* Writes the tag to the specified file + * Arg 1 - The tag list to be added to file - may be NULL for deleting all tags + * Arg 2 - The files name/file descriptor + * Returns - 0 on success or one of the following errors + * MP_EERROR - General failure: may occure on wrong usage, but should never happen + * MP_EVERSION - Function isn't able to handle a tag of this version + */ +extern int mp_write_to_file __P((const id3_tag_list*, const char*)); +extern int mp_write_to_fd __P((const id3_tag_list*, int)); + +/* Deletes all tags in file + * Arg 1 - The filename of fd + * Return - 0 on success + */ +extern int mp_del_tags_from_file __P((const char*)); +extern int mp_del_tags_from_fd __P((int)); + +/* Deletes all tags in file with the specified version + * Arg 1 - The filename or fd + * Arg 2 - The version + */ +extern int mp_del_tags_by_ver_from_file __P((const char*, int)); +extern int mp_del_tags_by_ver_from_fd __P((int, int)); + +/* Converts a tag to id3v1 or id3v2 tag format + * Arg 1 - The tag to be converted + * Returns - 0 on success or one of the following errors + * MP_EVERSION - Function isn't able to handle a tag of this version + */ +extern int mp_convert_to_v1 __P((id3_tag*)); +extern int mp_convert_to_v2 __P((id3_tag*)); + +/* Checks wether the given value would be a valid v1 field + * Arg 1 - The field + * Arg 2 - The value + * Returns - 0 if test failed + */ +extern int mp_is_valid_v1_value __P((int, char*)); + +/* Parses a content field + * Arg 1 - the content to parse + * Returns - A pointer to a new initialized structure suitable for the content + * or NULL + * On NULL: errno set to the following values + * MP_EERROR - General failure: may occure on wrong usage, but should never happen + * MP_EFENCR - The value for this field has been encrypted and can thus not be retrieved + * MP_EFCOMPR - The value for this field has been compressed and can thus not be retrieved + */ +extern id3_text_content *mp_parse_artist __P((const id3_content*)); +extern id3_text_content *mp_parse_title __P((const id3_content*)); +extern id3_text_content *mp_parse_album __P((const id3_content*)); +extern id3_text_content *mp_parse_year __P((const id3_content*)); +extern id3_text_content *mp_parse_genre __P((const id3_content*)); +extern id3_text_content *mp_parse_track __P((const id3_content*)); +extern id3_text_content *mp_parse_text __P((const id3_content*)); +extern id3_comment_content *mp_parse_comment __P((const id3_content*)); + +/* Assembles content from a comont text content + * Arg 1 - the text + * Arg 2 - the texts encoding (NULL) + * Returns - A pointer to a new initialized content structure + */ +extern id3_content *mp_assemble_text_content __P((const char*, id3_encoding)); + +/* Assembles content from a comment + * Arg 1 - the text + * Arg 2 - a short describtion to the text (NULL) + * Arg 3 - the texts encoding + * Arg 4 - the comments language (NULL) + * Returns - A pointer to a new initialized content structure + */ +extern id3_content *mp_assemble_comment_content __P((const char*, const char*, id3_encoding, const char*)); + +/* Gets a new allocated tag */ +extern id3_tag* mp_alloc_tag __P((void)); +extern id3_tag* mp_alloc_tag_with_version __P((int)); + +/* Frees tag struct */ +extern void mp_free_tag __P((id3_tag *)); + +__END_DECLS + +#endif /* __MPLIB_H */ diff --git a/libmpio/mplib/mplib_paas.c b/libmpio/mplib/mplib_paas.c new file mode 100644 index 0000000..441e474 --- /dev/null +++ b/libmpio/mplib/mplib_paas.c @@ -0,0 +1,256 @@ +/* + * mplib - a library that enables you to edit ID3 tags + * Copyright (C) 2001,2002 Stefan Podkowinski + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library 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 + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#if STDC_HEADERS +# include +# include +#elif HAVE_STRINGS_H +# include +#endif /*STDC_HEADERS*/ + +#if HAVE_UNISTD_H +# include +# include +#endif + +#include +#include +#include + +#include "mplib.h" +#include "xmalloc.h" + + + +/******************************************************************************************* + * Parse functions + *******************************************************************************************/ + + id3_text_content* + mp_parse_artist(const id3_content* content) + { + return mp_parse_text(content); + } + + id3_text_content* + mp_parse_title(const id3_content* content) + { + return mp_parse_text(content); + } + + id3_text_content* + mp_parse_album(const id3_content* content) + { + return mp_parse_text(content); + } + + id3_text_content* + mp_parse_year(const id3_content* content) + { + return mp_parse_text(content); + } + + id3_text_content* + mp_parse_genre(const id3_content* content) + { + return mp_parse_text(content); + } + + id3_text_content* + mp_parse_track(const id3_content* content) + { + return mp_parse_text(content); + } + + id3_comment_content* + mp_parse_comment(const id3_content* content) + { + id3_comment_content* cc; + int i, e; + + if(!content || !content->data) + { + errno = MP_EERROR; + return NULL; + } + + if(content->encrypted) + { + errno = MP_EFENCR; + return NULL; + } + if(content->compressed) + { + errno = MP_EFCOMPR; + return NULL; + } + + cc = XMALLOCD0(id3_comment_content, "mp_parse_comment:cc"); + + e = content->data[0]; + if(e >= ISO_8859_1 && e <= UTF8) cc->encoding = e; + else cc->encoding = 0; + + cc->language = xmallocd(4, "mp_parse_comment:cc->language"); + cc->language[0] = content->data[1]; + cc->language[1] = content->data[2]; + cc->language[2] = content->data[3]; + cc->language[3] = 0; + + if(content->data[4]) /* short descr. */ + { + i = strlen(content->data + 4) + 1; + cc->short_descr = xmallocd(i, "mp_parse_comment:cc->short_descr"); + strncpy(cc->short_descr, content->data + 4, i); + } + else + { + cc->short_descr = NULL; + i = 1; + } + + cc->text = xmallocd(content->length - 4 - i + 1, "mp_parse_comment:cc->text"); + memcpy(cc->text, content->data + 4 + i, content->length - 4 - i); + cc->text[content->length - 4 - i] = 0; + + return cc; + } + + id3_text_content* + mp_parse_text(const id3_content* content) + { + id3_text_content* tc; + int e; + + if(!content || !content->data) + { + errno = MP_EERROR; + return NULL; + } + + if(content->encrypted) + { + errno = MP_EFENCR; + return NULL; + } + if(content->compressed) + { + errno = MP_EFCOMPR; + return NULL; + } + + tc = XMALLOCD0(id3_text_content, "mp_parse_text:tc"); + tc->text = xmallocd(content->length, "mp_parse_text:tc->text"); + e = content->data[0]; + if(e >= ISO_8859_1 && e <= UTF8) tc->encoding = e; + else tc->encoding = 0; + + memcpy(tc->text, content->data + 1, content->length - 1); + tc->text[content->length - 1] = 0; + /* XXX multiple entries */ + return tc; + } + + /******************************************************************************************* + * Assemble functions + *******************************************************************************************/ + + id3_content* + mp_assemble_artist_content(const char* text, id3_encoding enc) + { + return mp_assemble_text_content(text, enc); + } + + id3_content* + mp_assemble_title_content(const char* text, id3_encoding enc) + { + return mp_assemble_text_content(text, enc); + } + + id3_content* + mp_assemble_album_content(const char* text, id3_encoding enc) + { + return mp_assemble_text_content(text, enc); + } + + id3_content* + mp_assemble_year_content(const char* text, id3_encoding enc) + { + return mp_assemble_text_content(text, enc); + } + + id3_content* + mp_assemble_genre_content(const char* text, id3_encoding enc) + { + return mp_assemble_text_content(text, enc); + } + + id3_content* + mp_assemble_text_content(const char* text, id3_encoding enc) + { + id3_content *ret; + + if(!text) return NULL; + + ret = XMALLOCD0(id3_content, "mp_assemble_text_content:ret"); + ret->length = strlen(text) + 1; + ret->data = xmallocd(ret->length, "mp_asseble_text_content:ret->data"); + ret->data[0] = enc; + strncpy(ret->data + 1, text, strlen(text)); + + return ret; + } + + id3_content* + mp_assemble_comment_content(const char* text, const char* short_descr, id3_encoding enc, const char* lang) + { + id3_content *ret; + + if(!text) return NULL; + + ret = XMALLOCD0(id3_content, "mp_assemble_comment_content:ret"); + ret->length = strlen(text) + 5; + if(short_descr) ret->length += strlen(short_descr); + + ret->data = xmallocd(ret->length, "mp_assemble_comment_content:ret->data"); + ret->data[0] = enc; + if(lang && strlen(lang) == 3) + { + ret->data[1] = lang[0]; + ret->data[2] = lang[1]; + ret->data[3] = lang[2]; + } + else + { + ret->data[1] = 'X'; + ret->data[2] = 'X'; + ret->data[3] = 'X'; + } + if(short_descr) strcpy(ret->data + 4, short_descr); + else ret->data[4] = 0; + + if(short_descr) strncpy(ret->data + 5 + strlen(short_descr), text, strlen(text)); + else strncpy(ret->data + 5, text, strlen(text)); + + return ret; + + } diff --git a/libmpio/mplib/mplib_s.c b/libmpio/mplib/mplib_s.c new file mode 100644 index 0000000..2c336b4 --- /dev/null +++ b/libmpio/mplib/mplib_s.c @@ -0,0 +1,1177 @@ +/* + * mplib - a library that enables you to edit ID3 tags + * Copyright (C) 2001,2002 Stefan Podkowinski + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library 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 + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#if STDC_HEADERS +# include +# include +#elif HAVE_STRINGS_H +# include +#endif /*STDC_HEADERS*/ + +#if HAVE_UNISTD_H +# include +# include +#endif + + +#include +#include +#include +#include +#include + +#include "mplib_s.h" +#include "xmalloc.h" + + + +/******************************/ +/* Static functions */ +/******************************/ + +static id3v1_tag* +id3v1_get_tag(int fd) +{ + id3v1_tag *tag; + char *c; + + tag = XMALLOCD0(id3v1_tag, "id3v1_get_tag:tag"); + + c = (char *)xmallocd(3, "id3v1_get_tag:c"); + + if(lseek(fd, -128L, SEEK_END) == -1) goto exit_on_error; + if(read(fd, c, 3) < 3) goto exit_on_error; + if(strncmp(c, "TAG", 3) != 0) goto exit_on_error; + + tag->title = (char *)xmallocd(31, "id3v1_get_tag:tag->title"); + if(read(fd, tag->title, 30) < 30) goto exit_on_error; + if(tag->title[0] == 0 || id3_is_only_space(tag->title, 30)) { + xfree(tag->title); + tag->title = NULL; + } else tag->title[30] = 0; + + tag->artist = (char*)xmallocd(31, "id3v1_get_tag:tag->artist"); + if(read(fd, tag->artist, 30) < 30) goto exit_on_error; + if(tag->artist[0] == 0 || id3_is_only_space(tag->artist, 30)) { + xfree(tag->artist); + tag->artist = NULL; + } else tag->artist[30] = 0; + + tag->album = (char*)xmallocd(31, "id3v1_get_tag:tag->album"); + if(read(fd, tag->album, 30) < 30) goto exit_on_error; + if(tag->album[0] == 0 || id3_is_only_space(tag->album, 30)) { + xfree(tag->album); + tag->album = NULL; + } else tag->album[30] = 0; + + tag->year = (char*)xmallocd(5, "id3v1_get_tag:tag->year"); + if(read(fd, tag->year, 4) < 4) goto exit_on_error; + if(tag->year[0] == 0 || id3_is_only_space(tag->year, 4)) { + xfree(tag->year); + tag->year = NULL; + } else tag->year[4] = 0; + + tag->comment = (char*)xmallocd(31, "id3v1_get_tag:tag->comment"); + if(read(fd, tag->comment, 30) < 30) goto exit_on_error; + tag->comment[30] = 0; + + if(read(fd, &(tag->genre), 1) < 1) goto exit_on_error; + + /* Looking for v1.1 track info */ + if(tag->comment && tag->comment[28] == 0 && tag->comment[29] != 0) + { + tag->track = tag->comment[29]; + tag->comment[29] = 0; + } + else + { + tag->track = 0; + } + + /* Set comment to NULL if not set - this happens at this point because */ + /* there maybe a track info anyway */ + if(tag->comment[0] == 0 || id3_is_only_space(tag->comment, 28)) { + xfree(tag->comment); + tag->comment = NULL; + } + + xfree(c); + return tag; + + exit_on_error: + + xfree(c); + id3v1_free_tag(tag); + return NULL; +} + +static int +id3v1_add_tag(int fd, id3v1_tag *tag) +{ + int i, j; + void *blank, *set; + char *b_tag, *b_tag_start; + + blank = xmallocd0(30, "id3v1_add_tag:blank"); + set = xmallocd(30, "id3v1_add_tag:set"); + memset(set, 0xFF, 30); + b_tag = b_tag_start = (char *)xmallocd0(128, "id3v1_add_tag:b_tag"); + + strncpy(b_tag, "TAG", 3); b_tag += 3; + + if(tag->title) + { + j = strlen(tag->title); + strncpy(b_tag, tag->title, j); b_tag += j; + i = 30 - j; + if(i > 0) + { + strncpy(b_tag, blank, i); b_tag += i; + } + } + else + { + strncpy(b_tag, blank, 30); b_tag += 30; + } + + if(tag->artist) + { + j = strlen(tag->artist); + strncpy(b_tag, tag->artist, j); b_tag += j; + i = 30 - j; + if(i > 0) + { + strncpy(b_tag, blank, i); b_tag += i; + } + } + else + { + strncpy(b_tag, blank, 30); b_tag += 30; + } + + if(tag->album) + { + j = strlen(tag->album); + strncpy(b_tag, tag->album, j); b_tag += j; + i = 30 - j; + if(i > 0) + { + strncpy(b_tag, blank, i); b_tag += i; + } + } + else + { + strncpy(b_tag, blank, 30); b_tag += 30; + } + + if(tag->year) + { + j = strlen(tag->year); + strncpy(b_tag, tag->year, j); b_tag += j; + i = 4 - j; + if(i > 0) + { + strncpy(b_tag, blank, i); b_tag += i; + } + } + else + { + strncpy(b_tag, blank, 4); b_tag += 4; + } + + if(tag->comment) + { + int hastrack = 0; + j = strlen(tag->comment); + if(tag->track > 0) hastrack = 1; + if(hastrack && j > 28) + { + strncpy(b_tag, tag->comment, 28); b_tag += 28; + } + else + { + strncpy(b_tag, tag->comment, j); b_tag += j; + i = ((tag->track > 0) ? 28 : 30) - j; + } + if(i > 0) + { + strncpy(b_tag, blank, i); b_tag += i; + } + } + else + { + strncpy(b_tag, blank, (tag->track > 0) ? 28 : 30); + b_tag += (tag->track > 0) ? 28 : 30; + } + + if(tag->track > 0) + { + strncpy(b_tag, blank, 1); b_tag += 1; + strncpy(b_tag, &(tag->track), 1); b_tag += 1; + } + if(tag->genre != 0xFF) + { + strncpy(b_tag, &(tag->genre), 1); b_tag += 1; + } + else + { + strncpy(b_tag, set, 1); b_tag += 1; + } + + j = 0; + + if(lseek(fd, 0L, SEEK_END) != -1) + { + if(write(fd, b_tag - 128, 128) < 128) j = 1; + } + else j = 1; + + xfree(b_tag_start); + xfree(blank); + xfree(set); + + return j; +} + +static int +id3v2_add_tag(int fd, id3v2_tag *tag, id3v2_tag *old) +{ + unsigned char *btag, *btag_start; + unsigned char flag = 0; + int i, j; + char *b_tag, *b_tag_start, *d; + id3v2_frame_list *frame_list; + id3v2_frame *frame; + + /* at first we are going to write the tags raw data into + the btag byte array */ + btag = btag_start = xmallocd0(tag->header->total_tag_size, + "id3v2_add_tag:btag"); + strncpy(btag, "ID3", 3); btag += 3; + *btag = (char)tag->header->version_minor; btag += 1; + *btag = (char)tag->header->version_revision; btag += 1; + flag |= ((tag->header->unsyncronization & 1) << 7); + flag |= ((tag->header->has_extended_header & 1) << 6); + flag |= ((tag->header->is_experimental & 1) << 5); + flag |= ((tag->header->has_footer & 1) << 4); + memcpy(btag, &flag, 1); btag += 1; + + if(old) + { + i = old->header->total_tag_size - 10; + if(old->header->has_footer) i -= 10; + } + else + { + i = tag->header->total_tag_size - 10; + if(tag->header->has_footer) i -= 10; + /* add padding to total size we mean to store on disk */ + /* mplib does not use any kind of padding internaly */ +/* i += 1024; */ /* no padding needed for MPIO use */ + } + + d = id3_sync32(i); + btag[0] = d[0]; + btag[1] = d[1]; + btag[2] = d[2]; + btag[3] = d[3]; + xfree(d); + btag += 4; + + if(tag->header->has_extended_header) + { + d = id3_sync32(tag->header->extended_header->size); + btag[0] = d[0]; + btag[1] = d[1]; + btag[2] = d[2]; + btag[3] = d[3]; + xfree(d); + btag += 4; + + *btag = (char)tag->header->extended_header->no_flag_bytes; btag += 1; + flag = ((tag->header->extended_header->is_update & 1) << 6); + flag |= ((tag->header->extended_header->crc_data_present & 1) << 5); + flag |= ((tag->header->extended_header->restrictions & 1) << 4); + memcpy(btag, &flag, 1); btag += 1; + if(tag->header->extended_header->is_update) + { + btag[0] = 0; btag += 1; + } + if(tag->header->extended_header->crc_data_present) + { + int length = tag->header->extended_header->crc_data_length ? tag->header->extended_header->crc_data_length : 5; + *btag = (char)length; btag += 1; + memcpy(btag, tag->header->extended_header->crc_data, length); btag += 1; + } + if(tag->header->extended_header->restrictions) + { + int length = tag->header->extended_header->restrictions_data_length ? tag->header->extended_header->restrictions_data_length : 5; + *btag = (char)length; btag += 1; + memcpy(btag, tag->header->extended_header->restrictions_data, length); btag += 1; + } + } + + frame_list = tag->frame_list; + while(frame_list) { + int j; + frame = frame_list->data; + + strncpy(btag, frame->frame_id, 4); btag += 4; + d = id3_sync32(frame->data_size); + btag[0] = d[0]; + btag[1] = d[1]; + btag[2] = d[2]; + btag[3] = d[3]; + xfree(d); + btag += 4; + memcpy(btag, &frame->status_flag, 1); btag += 1; + memcpy(btag, &frame->format_flag, 1); btag += 1; + + memcpy(btag, frame->data, frame->data_size); btag += frame->data_size; + + frame_list = frame_list->next; + } + + /* XXX footer not supported yet */ + + /* if an old tag was provided it is desired to overwrite it */ + /* else this is a brand new tag */ + if(old) { + FILE *file; + void *ptr = xmallocd0(old->header->total_tag_size - tag->header->total_tag_size, "id3v2_add_tag:ptr"); + if(!(file = fdopen(fd, "r+b"))) + { + xfree(ptr); + goto exit_on_error; + } + + fseek(file, 0, SEEK_SET); + if(fwrite(btag_start, tag->header->total_tag_size, 1, file) < 1) + { + xfree(ptr); + goto exit_on_error; + } + + /* write padding till end of old tag */ + if(fwrite(ptr, old->header->total_tag_size - tag->header->total_tag_size, 1, file) < 1) { + xfree(ptr); + goto exit_on_error; + } + + fflush(file); + xfree(ptr); + + } else { + FILE *file, *tmp; + int read; + void *ptr, *blank; + unsigned char *c; + + ptr = xmallocd(4096, "id3v2_add_tag:ptr"); + blank = xmallocd0(1024, "id3v2_add_tag:blank"); + + file = fdopen(fd, "r+b"); + tmp = tmpfile(); + if(!(file && tmp)) + { + fflush(file); + fclose(tmp); + xfree(ptr); + xfree(blank); + goto exit_on_error; + } + + fseek(file, 0, SEEK_SET); + fseek(tmp, 0, SEEK_SET); + + /* write tag in tmp file */ + fwrite(btag_start, tag->header->total_tag_size, 1, tmp); + + /* Write 1024b padding */ + /* no padding needed for MPIO use */ +/* fwrite(blank, 1024, 1, tmp); */ + + /* write rest of file */ + while(!feof(file)) + { + read = fread(ptr, 1, 4096, file); + if(fwrite(ptr, 1, read, tmp) != read && !feof(file)) + { + fflush(file); + fclose(tmp); + xfree(ptr); + xfree(blank); + goto exit_on_error; + } + } + + fflush(tmp); + + fseek(file, 0, SEEK_SET); + fseek(tmp, 0, SEEK_SET); + while(!feof(tmp)) + { + read = fread(ptr, 1, 4096, tmp); + if(fwrite(ptr, 1, read, file) != read && !feof(tmp)) + { + fflush(file); + fclose(tmp); + xfree(ptr); + xfree(blank); + goto exit_on_error; + } + } + + fflush(file); + fclose(tmp); + + xfree(ptr); + xfree(blank); + } + + xfree(btag_start); + return 0; + + exit_on_error: + xfree(btag_start); + return MP_EERROR; +} + +static int +id3v1_del_tag(int fd) +{ + int nlength; + unsigned char *c; + struct stat fs; + + if(fstat(fd, &fs)) return 1; + + if(fs.st_size < 128) return 1; /* Hardly a valid mpeg file.. */ + + c = (char *)xmallocd(3, "id3v1_del_tag:c"); + if(lseek(fd, -128L, SEEK_END) == -1) goto exit_on_error; + if(read(fd, c, 3) < 3) goto exit_on_error; + if(strncmp(c, "TAG", 3)) goto exit_on_error; + xfree(c); + + nlength = fs.st_size - 128; + + if(ftruncate(fd, nlength)) return 1; + + return 0; + + exit_on_error: + xfree(c); + return 1; +} + + +static int +id3v2_del_tag(int fd, id3v2_tag *t) +{ + unsigned char *c; + long tag_len, file_len; + FILE *file, *tmp; + int read; + void *ptr; + id3v2_tag *tfound = NULL;; + + if(!t) + { + t = id3v2_get_tag(fd); + if(!t) return 0; + else tfound = t; + } + + ptr = xmallocd(4096, "id3v2_del_tag:ptr"); + + tag_len = t->header->total_tag_size; + file_len = lseek(fd, 0, SEEK_END); + if(file_len < 1 || tag_len < 1) goto exit_on_error; + + /* use os system buffering */ + file = fdopen(fd, "r+b"); + tmp = tmpfile(); + if(!(file && tmp)) goto exit_on_error; + + fseek(file, tag_len, SEEK_SET); + fseek(tmp, 0, SEEK_SET); + while(!feof(file)) + { + read = fread(ptr, 1, 4096, file); + if(fwrite(ptr, 1, read, tmp) != read && !feof(file)) + goto exit_on_error; + } + + fflush(tmp); + + fseek(file, 0, SEEK_SET); + fseek(tmp, 0, SEEK_SET); + while(!feof(tmp)) + { + read = fread(ptr, 1, 4096, tmp); + if(fwrite(ptr, 1, read, file) != read && !feof(tmp)) + goto exit_on_error; + } + + fclose(tmp); + xfree(ptr); + if(tfound) id3v2_free_tag(tfound); + return 0; + + exit_on_error: + fclose(tmp); + xfree(ptr); + if(tfound) id3v2_free_tag(tfound); + return 1; +} + + +static int +id3v1_truncate_tag(id3v1_tag *tag) +{ + int notrunc = 0; + int len = 0; + void *ptr; + + if(tag->title && (len = strlen(tag->title)) > 30) + { + realloc(tag->title, 31); + tag->title[30] = 0; + } + + if(tag->artist && (len = strlen(tag->artist)) > 30) + { + realloc(tag->artist, 31); + tag->artist[30] = 0; + } + + if(tag->album && (len = strlen(tag->album)) > 30) + { + realloc(tag->album, 31); + tag->album[30] = 0; + } + + if(tag->year && (len = strlen(tag->year)) > 4) + { + realloc(tag->title, 5); + tag->title[4] = 0; + } + + if(tag->comment) + { + int max = (tag->track > 0) ? 28 : 30; + if((len = strlen(tag->comment)) > max) + { + realloc(tag->comment, max + 1); + tag->comment[max] = 0; + } + } + + return notrunc; +} + +static int +id3_is_only_space(char *str, int strlen) +{ + int i = 0; + + while(i < strlen) + { + if(str[i] != 0x20) return 0; + i++; + } + + return 1; +} + +static id3v2_tag* +id3v2_get_tag(int fd) +{ + unsigned char *c; + id3v2_header *header; + id3v2_frame_list *frame_list; + id3v2_frame *frame; + id3v2_tag *tag = NULL; + int i; + + if(lseek(fd, 0L, SEEK_SET) == -1) return NULL; + + c = (unsigned char*)xmallocd0(1024, "id3v2_get_tag:c"); + + if(read(fd, c, 10) < 10) goto exit_on_error; + + c[10] = 0; + + if(strncmp(c, "ID3", 3)) goto exit_on_error; + + header = XMALLOCD0(id3v2_header, "id3v2_get_tag:header"); + header->version_minor = c[3]; + header->version_revision = c[4]; + header->flags = c[5]; + header->unsyncronization = (c[5] & 128) >> 7; + header->has_extended_header = (c[5] & 64) >> 6; + header->is_experimental = (c[5] & 32) >> 5; + header->has_footer = (c[5] & 16) >> 4; + + header->total_tag_size = id3_unsync32(c, 6) + 10; + if(header->has_footer) header->total_tag_size += 10; + + tag = XMALLOCD0(id3v2_tag, "id3v2_get_tag:tag"); + + /* check if version is supported */ + if(c[3] != 3 && c[3] != 4) + { + xfree(c); + tag->header = header; + tag->frame_list = NULL; + return tag; + } + + frame_list = XMALLOCD0(id3v2_frame_list, "id3v2_get_tag:frame_list"); + frame_list->start = frame_list; + + /* assigning header and frame list to tag */ + tag->header = header; + tag->frame_list = frame_list; + + if(header->has_extended_header) + { + id3v2_extended_header *xt_header = XMALLOCD0(id3v2_extended_header, + "id3v2_get_tag:id3v2_extended_header"); + + header->extended_header = xt_header; + + read(fd, c, 4); /* get length of extended header */ + xt_header->size = id3_unsync32(c, 0); + + read(fd, c, 1); /* get number of flags */ + xt_header->no_flag_bytes = (c[0] > 0) ? c[0] : 1; + + read(fd, c, xt_header->no_flag_bytes); /* get flag bytes */ + xt_header->is_update = (c[0] & 64) >> 6; + xt_header->crc_data_present = (c[0] & 32) >> 5; + xt_header->restrictions = (c[0] & 16) >> 4; + + /* Flag data */ + if(xt_header->is_update) read(fd, c, 1); /* Data length ind. is 0 -skip */ + if(xt_header->crc_data_present) { + read(fd, c, 1); /* data length - shoud be 5 */ + if(*c != 5) goto exit_on_error; /* else things might + break badly */ + xt_header->crc_data_length = *c; + xt_header->crc_data = xmallocd0(*c, "id3v2_get_tag:xt_header->crc_data"); + read(fd, xt_header->crc_data, *c); + } + if(xt_header->restrictions) { + read(fd, c, 1); /* data length - shoud be 1 */ + if(*c != 1) goto exit_on_error; + xt_header->restrictions_data_length = *c; + xt_header->restrictions_data = xmallocd0(*c, + "id3v2_get_tag:xt_header->restrictions_data"); + read(fd, xt_header->restrictions_data, *c); + } + } + + /* Read frames */ + while(lseek(fd, 0L, SEEK_CUR) < header->total_tag_size) + { + int hasEnc = 0, hasLang = 0, d; + + read(fd, c, 10); /* Read header */ + + /* break if padding is reached - this should never happen here.. */ + if(c[0] == 0 && c[1] == 0 && c[2] == 0 && c[3] == 0) break; + + /* Check if possible id is alpha numeric */ + if(!isalnum(c[0]) || !isalnum(c[1]) || !isalnum(c[2]) || !isalnum(c[3])) break; + + frame = XMALLOCD(id3v2_frame, "id3v2_get_tag:frame"); + frame->frame_id = xmallocd(4, "id3v2_get_tag:frame->frame_id"); + strncpy(frame->frame_id, c, 4); + frame->data_size = id3_unsync32(c, 4); + frame->status_flag = c[8]; + frame->format_flag = c[9]; + + /* Getting frame content */ + frame->data = xmallocd(frame->data_size, "id3v2_get_tag:frame->data_size"); + read(fd, frame->data, frame->data_size); + + /* Add frame to list */ + if(frame_list->data) + { + frame_list->next = XMALLOCD(id3v2_frame_list, "id3v2_get_tag:frame_list->next"); + frame_list->next->start = frame_list->start; + frame_list = frame_list->next; + frame_list->next = NULL; + } + frame_list->data = frame; + } + + xfree(c); + return tag; + + exit_on_error: + + xfree(c); + id3v2_free_tag(tag); + return NULL; +} + +static char ** +id3v2_get_names(id3v2_tag *tag) +{ + id3v2_frame *frame; + id3v2_frame_list *frame_list; + char **clist; + int i; + + if(!tag->frame_list) return NULL; + + frame_list = tag->frame_list; + + i = id3_get_no_frames(tag); + clist = xmallocd(sizeof(char*) * i+1, "id3v2_get_names:clist"); + clist[i] = 0; + + for(i = 0; frame_list; i++) + { + if(!frame_list->data) continue; + frame = frame_list->data; + + if(!frame->frame_id) continue; + clist[i] = xmallocd(5, "id3v2_get_names:clist[i]"); + strncpy(clist[i], frame->frame_id, 4); + clist[i][4] = 0; + frame_list = frame_list->next; + } + return clist; +} + + +static id3_content* +id3v1_get_content(id3v1_tag *tag, int field) +{ + int i; + char *c; + id3_content *ret; + + switch(field) + { + case MP_ARTIST: + if(!tag->artist) + { + errno = MP_EFNF; + return NULL; + } + return mp_assemble_text_content(tag->artist, ISO_8859_1); + + case MP_TITLE: + if(!tag->title) + { + errno = MP_EFNF; + return NULL; + } + return mp_assemble_text_content(tag->title, ISO_8859_1); + + case MP_ALBUM: + if(!tag->album) + { + errno = MP_EFNF; + return NULL; + } + return mp_assemble_text_content(tag->album, ISO_8859_1); + + case MP_YEAR: + if(!tag->year) + { + errno = MP_EFNF; + return NULL; + } + return mp_assemble_text_content(tag->year, ISO_8859_1); + + case MP_COMMENT: + if(!tag->comment) + { + errno = MP_EFNF; + return NULL; + } + return mp_assemble_comment_content(tag->comment, NULL, ISO_8859_1, NULL); + + case MP_GENRE: + if(tag->genre < GLL) + { + return mp_assemble_text_content(genre_list[tag->genre], ISO_8859_1); + } + else + { + errno = MP_EFNF; + return NULL; + } + + case MP_TRACK: + if(!tag->track) + { + errno = MP_EFNF; + return NULL; + } + + if(tag->track < 10) i = 2; + else if(tag->track < 100) i = 3; + else i = 4; + c = xmallocd(i, "id3v1_get_content:c"); + snprintf(c, i, "%d", tag->track); + ret = mp_assemble_text_content(c, ISO_8859_1); + xfree(c); + return ret; + + default: + errno = MP_EFNF; + return NULL; + } +} + +static id3_content* +id3v2_get_content_at_pos(id3v2_tag *tag, const char *field, int pos) +{ + id3v2_frame_list *frame_list; + id3v2_frame *frame; + int i, found, j; + + if(!tag->frame_list || !field) + { + errno = MP_EERROR; + return NULL; + } + + frame_list = tag->frame_list; + + for(i = 0, found = 0; frame_list; i++, frame_list = frame_list->next) + { + if(!frame_list->data) continue; + frame = frame_list->data; + + if(!frame->frame_id || !frame->data) continue; + if(strncmp(frame->frame_id, field, 4)) continue; + + if(found == pos) + { + id3_content *ret = XMALLOCD0(id3_content, + "id3v2_get_content_at_pos:ret"); + if(frame_is_compressed(frame)) ret->compressed = 1; + else ret->compressed = 0; + + if(frame_is_encrypted(frame)) ret->encrypted = 1; + else ret->encrypted = 0; + + ret->length = frame->data_size; + ret->data = xmallocd(frame->data_size, "id3v2_get_content_at_pos:ret->data"); + ret->data = memcpy(ret->data, frame->data, frame->data_size); + + return ret; + } + + found++; + } + + errno = MP_EFNF; + return NULL; +} + +static long +id3_sync(unsigned char* data, long length) +{ + int i; + + for(i = 0; i < length - 1; i++) + { + if(((data[i] & 0xFF) == 0xFF && (data[i+1] & 0xE0) == 0xE0) || + (i+2 < length && (data[i] & 0xFF) == 0xFF && data[i+1] == 0 && data[i+2] != 0)) + { + + realloc(data, length + 1); length++; + memmove(data + i+2, data + i+1, length - i - 2); + memset(data + i+1, 0, 1); + } + } + + return length; +} + +static long +id3_unsync(unsigned char* data, long length) +{ + /* TODO */ + /* this function is supposed to make syncsafe values normal again */ + /* we don't need this yet, because there are no fields supported that will */ + /* have the unsynchronization scheme applied */ + + +} + +static unsigned int +id3_unsync32(unsigned char* c, int start) +{ + return c[start+3] + (c[start+2] << 7) + (c[start+1] << 14) + (c[start] << 21); +} + +int +id3_get_no_frames(id3v2_tag *tag) +{ + int i; + id3v2_frame_list *frame_list = tag->frame_list; + + for(i = 0; frame_list; i++) + frame_list = frame_list->next; + + return i; +} + +static unsigned char * +id3_sync32(unsigned int i) +{ + unsigned char *c = (unsigned char *)xmallocd0(4, "id3_sync32:c"); + + c[3] = (i & 0x7f); + c[2] = ((i & 0x80) >> 7) | (((i & 0x7f00) >> 8) << 1); + c[1] = ((i & 0x8000) >> 15) | (((i & 0x7f0000) >> 16) << 1); + c[0] = ((i & 0x800000) >> 23) | (((i & 0x7f000000) >> 24) << 1); + + return c; +} + +id3v2_frame* +id3_lookup_frame(id3v2_frame_list *list, const char *field, const int pos) +{ + int cur = 0; + + if(!list || !field) return NULL; + + do + { + if(!strcmp(list->data->frame_id, field)) + { + if(cur == pos) return list->data; + cur++; + } + } while((list = list->next)); + + return NULL; +} + +int +id3_remove_frame(id3v2_frame_list *list, id3v2_frame *frame) +{ + if(!list || !frame) return MP_EERROR; + + /* Frame is first element in list */ + if(list->data == frame) + { + xfree(list->data); + list->next->start = list->next; + xfree(list); + return 0; + } + + /* Iterate through others */ + do + { + if(list->next->data == frame) + { + list->next = list->next->next; + xfree(frame); + return 0; + } + } while((list = list->next)); + + return 1; +} + + +int +id3_add_frame(id3v2_frame_list *list, char *field, char *new_value, int len) +{ + id3v2_frame *frame; + char *new_valuecp; + long len_sync; + + if(!list || !new_value || !field || strlen(field) != 4) return MP_EERROR; + + // make a copy of the given value to include it in the frame + new_valuecp = xmallocd(len, + "id3_add_frame:new_valuecp"); + memcpy(new_valuecp, new_value, len); + new_value = new_valuecp; + + /* make sync safe */ +/* len_sync = id3_sync(new_value, len); */ + len_sync = len; /* disabled sync for MPIO use */ + + frame = XMALLOCD(id3v2_frame, "id3_add_frame:frame"); + frame->frame_id = xmallocd(4, "id3_add_frame:frame->frame_id"); + strncpy(frame->frame_id, field, 4); + frame->data = new_value; + frame->status_flag = 0; + + if(len != len_sync) frame->format_flag = 64; + else frame->format_flag = 0; + frame->data_size = len_sync; + + /* Empty list */ + if(!list->data) + { + list->data = frame; + return 0; + } + + /* iterate to last element */ + while(list->next) list = list->next; + + list->next = XMALLOCD(id3v2_frame_list, "id3_add_frame:list->next"); + list->next->start = list->start; + list = list->next; + list->next = NULL; + list->data = frame; + + return 0; +} + + +#define BUF_SIZE 4096 + +static int +id3_lseek_syncword(int fd) +{ + unsigned char *data = (unsigned char*) xmallocd(BUF_SIZE, "id3_lseek_syncword:data"); + int ret; + + // Reset the reading offset of the fd + lseek(fd, SEEK_SET, 0); + + if(read(fd, data, BUF_SIZE) < 1) + { + xfree(data); + return 0; /* return false on EOF */ + } + + ret = id3_lseek_syncword_r(fd, data, 0); + xfree(data); + return ret; +} + +static int +id3_lseek_syncword_r(int fd, unsigned char *data, int checked) +{ + unsigned char lastchar; + int i; + + for(i = 0; i + 1 < BUF_SIZE; i++) + { + if(((data[i] & 0xFF)== 0xFF) && ((data[i+1] & 0xE0)== 0xE0)) + { + lseek(fd, checked + i, SEEK_SET); + return 0; + } + } + + lastchar = data[BUF_SIZE - 1]; + + if(read(fd, data, BUF_SIZE) < 1) return 0; /* return false on EOF */ + + if(((lastchar & 0xFF)== 0xFF) && ((data[0] & 0xE0)== 0xE0)) + { + lseek(fd, checked + BUF_SIZE - 1, SEEK_SET); + return 0; + } + + return id3_lseek_syncword_r(fd, data, checked + BUF_SIZE); +} + +static id3_tag* +id3v1_alloc_tag(void) +{ + id3_tag *tag = XMALLOCD(id3_tag, "id3v1_alloc_tag:tag"); + id3v1_tag *v1 = XMALLOCD0(id3v1_tag, "id3v1_alloc_tag:v1"); + + tag->tag = v1; + tag->version = 1; + + v1->genre = 0xFF; + + return tag; +} + +static id3_tag* +id3v2_alloc_tag(void) +{ + id3_tag *tag = XMALLOCD(id3_tag, "id3v2_alloc_tag:tag"); + id3v2_tag *v2 = XMALLOCD0(id3v2_tag, "id3v2_alloc_tag:v2"); + + tag->tag = v2; + tag->version = 2; + + return tag; +} + +static void +id3v1_free_tag(id3v1_tag* v1) +{ + xfree(v1->artist); + xfree(v1->album); + xfree(v1->title); + xfree(v1->year); + xfree(v1->comment); + xfree(v1); +} + +static void +id3v2_free_tag(id3v2_tag* v2) +{ + id3v2_frame_list* doomed; + id3v2_frame *frame; + + if(!v2) return; + + xfree(v2->header->extended_header); + xfree(v2->header); + + if(!v2->frame_list) + { + xfree(v2); + return; + } + + /* Freeing frames */ + do + { + frame = (id3v2_frame*)v2->frame_list->data; + if(frame->frame_id) xfree(frame->frame_id); + if(frame->data) xfree(frame->data); + xfree(v2->frame_list->data); + + doomed = v2->frame_list->next; + xfree(v2->frame_list); + + } while((v2->frame_list = doomed)); + + xfree(v2); +} diff --git a/libmpio/mplib/mplib_s.h b/libmpio/mplib/mplib_s.h new file mode 100644 index 0000000..7803a5e --- /dev/null +++ b/libmpio/mplib/mplib_s.h @@ -0,0 +1,153 @@ +/* + * mplib - a library that enables you to edit ID3 tags + * Copyright (C) 2001,2002 Stefan Podkowinski + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library 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 + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "mplib.h" + +#ifndef __MPLIB_S_H +#define __MPLIB_S_H + +#undef __BEGIN_DECLS +#undef __END_DECLS +#ifdef __cplusplus +# define __BEGIN_DECLS extern "C" { +# define __END_DECLS } +#else +# define __BEGIN_DECLS /* empty */ +# define __END_DECLS /* empty */ +#endif + + +__BEGIN_DECLS + + +/************************************/ +/* Members */ +/************************************/ + +/* Bitrates br_[version]_[layer] ) */ +const static int br_1_1[16] = { -1, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0 }; +const static int br_1_2[16] = { -1, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 0 }; +const static int br_1_3[16] = { -1, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0 }; +const static int br_2_1[16] = { -1, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0 }; +const static int br_2_2[16] = { -1, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 0 }; +const static int br_2_3[16] = { -1, 8, 16, 24, 32, 64, 80, 56, 64, 128, 160, 112, 128, 256, 320, 0 }; + +#define GLL 148 +const static char *genre_list[GLL] = +{ "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge", "Hip-Hop", "Jazz", + "Metal", "New Age", "Oldies", "Other", "Pop", "R&B", "Rap", "Reggae", "Rock", "Techno", + "Industrial", "Alternative", "Ska", "Death Metal", "Pranks", "Soundtrack", "Euro-Techno", + "Ambient", "Trip-Hop", "Vocal", "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental", + "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise", "Alternative Rock", "Bass", "Soul", "Punk", + "Space", "Meditative", "Instrumental Pop", "Instrumental Rock", "Ethnic", "Gothic", "Darkwave", + "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream", "Southern Rock", "Comedy", + "Cult", "Gangsta Rap", "Top 40", "Christian Rap", "Pop/Funk", "Jungle", "Native American", "Cabaret", + "New Wave", "Psychedelic", "Rave", "Showtunes", "Trailer", "Lo-Fi", "Tribal", "Acid Punk", + "Acid Jazz", "Polka", "Retro", "Musical", "Rock & Roll", "Hard Rock", "Folk", "Folk/Rock", + "National Folk", "Swing", "Fast-Fusion", "Bebob", "Latin", "Revival", "Celtic", "Bluegrass", + "Avantgarde", "Gothic Rock", "Progressive Rock", "Psychedelic Rock", "Symphonic Rock", "Slow Rock", + "Big Band", "Chorus", "Easy Listening", "Acoustic", "Humour", "Speech", "Chanson", "Opera", + "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus", "Porn Groove", "Satire", "Slow Jam", + "Club", "Tango", "Samba", "Folklore", "Ballad", "Power Ballad", "Rythmic Soul", "Freestyle", + "Duet", "Punk Rock", "Drum Solo", "A Cappella", "Euro-House", "Dance Hall", "Goa", "Drum & Bass", + "Club-House", "Hardcore", "Terror", "Indie", "BritPop", "Negerpunk", "Polsk Punk", "Beat", + "Christian Gangsta Rap", "Heavy Metal", "Black Metal", "Crossover", "Contemporary Christian", + "Christian Rock", "Merengue", "Salsa", "Trash Metal", "Anime", "JPop", "Synthpop" }; + + +/************************************/ +/* Macros */ +/************************************/ + +#define frame_is_read_only(id3v2_frame__) ((id3v2_frame__->status_flag >> 4) & 1) +#define frame_preserve_on_tag_altered(id3v2_frame__) ((id3v2_frame__->status_flag >> 6) & 1) +#define frame_preserve_on_file_altered(id3v2_frame__) ((id3v2_frame__->status_flag >> 5) & 1) + +#define frame_has_group_information(id3v2_frame__) ((id3v2_frame__->format_flag >> 6) & 1) +#define frame_is_compressed(id3v2_frame__) ((id3v2_frame__->format_flag >> 3) & 1) +#define frame_is_encrypted(id3v2_frame__) ((id3v2_frame__->format_flag >> 2) & 1) +#define frame_is_unsynchronised(id3v2_frame__) ((id3v2_frame__->format_flag >> 1) & 1) +#define frame_has_data_length_indicator(id3v2_frame__) (id3v2_frame__->format_flag & 1) + + +/************************************/ +/* Static functions */ +/************************************/ + + +/* Gets the v1/v2 tag from a file */ +static id3v1_tag *id3v1_get_tag(int); +static id3v2_tag *id3v2_get_tag(int); + +/* Adds v1/v2 Tag to file */ +static int id3v1_add_tag(int, id3v1_tag*); +static int id3v2_add_tag(int, id3v2_tag*, id3v2_tag*); + +/* Removes v1/v2 Tag from file */ +static int id3v1_del_tag(int); +static int id3v2_del_tag(int, id3v2_tag*); + +/* Truncates the fields of the tag to the proper lengths */ +static int id3v1_truncate_tag(id3v1_tag*); + +/* Returns 1 or 0 whether arg 1 is just filled up with space (0x20) or not */ +static int id3_is_only_space(char*, int); + +/* Gets all frame names available in the tag */ +static char **id3v2_get_names(id3v2_tag*); + +/* Gets the content of the given field in the tag on the specified position. */ +static id3_content* id3v2_get_content_at_pos(id3v2_tag*, const char*, int); +static id3_content* id3v1_get_content(id3v1_tag*, int); + +/* Gets the number of available frames */ +static int id3_get_no_frames(id3v2_tag*); + +/* Returns string of the frames content */ +/* static char* extract_frame_data(char *, int); */ + +/* Removes a frame from the frame list */ +static int id3_remove_frame(id3v2_frame_list *, id3v2_frame *); + +/* Adds a new frame to the list */ +static int id3_add_frame(id3v2_frame_list *, char *, char *, int); + +/* Lookups a frame by his identifier on the given position */ +static id3v2_frame* id3_lookup_frame(id3v2_frame_list *, const char *, const int); + +/* Sync functions */ +static long id3_unsync(unsigned char*, long); +static long id3_sync(unsigned char*, long); +static unsigned int id3_unsync32(unsigned char*, int); +static unsigned char* id3_sync32(unsigned int); + +static int id3_lseek_syncword(int); +static int id3_lseek_syncword_r(int, unsigned char *, int); + +/* Gets a new allocated v1 or v2 tag */ +static id3_tag* id3v1_alloc_tag(void); +static id3_tag* id3v2_alloc_tag(void); + +/* free functions */ +static void id3v1_free_tag(id3v1_tag*); +static void id3v2_free_tag(id3v2_tag*); + + +__END_DECLS + +#endif /* __MPLIB_S_H */ diff --git a/libmpio/mplib/xmalloc.c b/libmpio/mplib/xmalloc.c new file mode 100644 index 0000000..a66be63 --- /dev/null +++ b/libmpio/mplib/xmalloc.c @@ -0,0 +1,167 @@ +/* + * mplib - a library that enables you to edit ID3 tags + * Copyright (C) 2001,2002 Stefan Podkowinski + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library 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 + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +/* define XMALLOC_CHECK 1 */ +#include "xmalloc.h" +#ifdef USE_GC +# include +# define malloc(str) GC_MALLOC(str) +#endif + +#ifdef XMALLOC_CHECK +typedef struct _xdelem { + void* alloced; + void* freed; + char* descrl; + struct _xdelem* next; +} xdelem; + +xdelem* first = NULL; +#endif + +#define errmsg "mplib: Memory exhausted: Could not allocate %d bytes\n" + +void * +xmalloc(size_t s) +{ + return xmallocd(s, NULL); +} + +void * +xmallocd(size_t s, char* descrl) +{ + void *new = (void*)malloc(s); +#ifdef XMALLOC_CHECK + xdelem* cur = (xdelem*)malloc(sizeof(xdelem)); + cur->next = NULL; + cur->freed = NULL; + cur->descrl = descrl; +#endif + if(!new) fprintf(stderr, errmsg, s); + +#ifdef XMALLOC_CHECK + cur->alloced = new; + exists: + if(!first) first = cur; + else { + xdelem* last = first; + do { + if(last->alloced == cur->alloced) { + last->freed = NULL; + last->descrl = descrl; + free(cur); + goto exists; + } + } while(last->next && (last = last->next)); + last->next = cur; + } +#endif + + return new; +} + +void * +xmallocd0(size_t s, char* descr) +{ +#ifdef XMALLOC_CHECK + void *new = (void*)xmallocd(s, descr); +#else + void *new = (void*)malloc(s); +#endif + if(!new) fprintf(stderr, errmsg, s); + else memset(new, 0, s); + return new; +} + +void * +xmalloc0(size_t s) +{ +#ifdef XMALLOC_CHECK + void *new = (void*)xmalloc(s); +#else + void *new = (void*)malloc(s); +#endif + if(!new) fprintf(stderr, errmsg, s); + else memset(new, 0, s); + return new; +} + +void * +xrealloc(void * ptr, size_t s) +{ + void *new; + + if(!ptr) return xmalloc(s); + + new = (void*)realloc(ptr, s); + if(!new) fprintf(stderr, errmsg, s); + return new; +} + +void +xfree(void* ptr) { + if(!ptr) return; +#ifdef XMALLOC_CHECK + if(first) { + xdelem* el = first; + do { + if(el->freed == ptr) { + if(el->descrl) + printf("XMALLOC: (%s) memory allready freed\n", el->descrl); + else + printf("XMALLOC: memory allready freed at %h\n", ptr); + break; + } + if(el->alloced == ptr) { + el->freed = ptr; + break; + } + } while(el->next && (el = el->next)); + } +#endif + free(ptr); +} + + +#ifdef XMALLOC_CHECK +void +xprint_malloc_stat(void) { + long kb_alloc = 0; + long kb_freed = 0; + long kb_used = 0; + int count_used = 0; + xdelem* el = first; + + if(!first) { + puts("XMALLOC: No statistic available"); + } + puts("xmalloc statistic:"); + do { + if(!el->freed) { + if(el->descrl && !strstr(el->descrl, "ignore")) + printf("%s (not freed)\n", el->descrl); + else if(!el->descrl) printf("%p (not freed)\n", el->alloced); + } else { + //if(el->descrl) printf("%s (freed)\n", el->descrl); + //else printf("%p (freed)\n", el->alloced); + } + } while(el->next && (el = el->next)); +} +#endif diff --git a/libmpio/mplib/xmalloc.h b/libmpio/mplib/xmalloc.h new file mode 100644 index 0000000..ecdf1b6 --- /dev/null +++ b/libmpio/mplib/xmalloc.h @@ -0,0 +1,58 @@ +/* + * mplib - a library that enables you to edit ID3 tags + * Copyright (C) 2001,2002 Stefan Podkowinski + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; version 2.1. + * + * This library 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 + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __XMALLOC_H +#define __XMALLOC_H + +/* __BEGIN_DECLS should be used at the beginning of your declarations, + so that C++ compilers don't mangle their names. Use __END_DECLS at + the end of C declarations. */ +#undef __BEGIN_DECLS +#undef __END_DECLS +#ifdef __cplusplus +# define __BEGIN_DECLS extern "C" { +# define __END_DECLS } +#else +# define __BEGIN_DECLS /* empty */ +# define __END_DECLS /* empty */ +#endif + + +#define XMALLOC(type) ((type *) xmalloc(sizeof(type))) +#define XMALLOCD(type,descr) ((type *) xmallocd(sizeof(type),descr)) +#define XMALLOC0(type) ((type *) xmalloc0(sizeof(type))) +#define XMALLOCD0(type,descr) ((type *) xmallocd0(sizeof(type),descr)) + +__BEGIN_DECLS + +/* define XMALLOC_CHECK 1 */ + +void *xmalloc(size_t); +void *xmallocd(size_t, char*); +void *xmalloc0(size_t); +void *xmallocd0(size_t, char*); +void *xrealloc(void *, size_t); +void *xcalloc(size_t, size_t); +void xfree(void*); +#ifdef XMALLOC_CHECK +void xprint_malloc_stat(void); +#endif + +__END_DECLS + +#endif /* __XMALLOC_H */ diff --git a/libmpio/smartmedia.c b/libmpio/smartmedia.c deleted file mode 100644 index 9a34683..0000000 --- a/libmpio/smartmedia.c +++ /dev/null @@ -1,153 +0,0 @@ -/* -*- linux-c -*- */ - -/* - * - * $Id: smartmedia.c,v 1.3 2003/04/21 09:17:38 germeier Exp $ - * - * Library for USB MPIO-* - * - * Markus Germeier (mager@tzi.de) - * - * - * - * 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 -#include - -#include "smartmedia.h" -#include "debug.h" - -mpio_disk_phy_t MPIO_DISK_GEO_001={ 125, 4, 4, 2000 }; -mpio_disk_phy_t MPIO_DISK_GEO_002={ 125, 4, 8, 4000 }; -mpio_disk_phy_t MPIO_DISK_GEO_004={ 250, 4, 8, 8000 }; -mpio_disk_phy_t MPIO_DISK_GEO_008={ 250, 4, 16, 16000 }; -mpio_disk_phy_t MPIO_DISK_GEO_016={ 500, 4, 16, 32000 }; -mpio_disk_phy_t MPIO_DISK_GEO_032={ 500, 8, 16, 64000 }; -mpio_disk_phy_t MPIO_DISK_GEO_064={ 500, 8, 32, 128000 }; -mpio_disk_phy_t MPIO_DISK_GEO_128={ 500,16, 32, 256000 }; - -/* This comes from the Samsung documentation files */ - -/* a small warning: only use this function (mpio_id2mem) in the very - * beginning of MPIO model detection. After that use the values - * of size and chips! -mager - */ - -int -mpio_id2mem(BYTE id) -{ - int i=0; - - switch(id) - { - case 0xea: - i=2; - break; - case 0xe3: /* Samsung */ - case 0xe5: /* Toshiba */ - i=4; - break; - case 0xe6: - i=8; - break; - case 0x73: - i=16; - break; - case 0x75: - i=32; - break; - case 0x76: - i=64; - break; - case 0x79: - i=128; - break; - default: - debug("This should never happen (id2mem)!\n"); - exit (1); - } - return i; -} - -BYTE * -mpio_id2manufacturer(BYTE id) -{ - BYTE *m; - switch(id) - { - case 0xec: - m="Samsung"; - break; - case 0x98: - m="Toshiba"; - break; - default: - m="unknown"; - } - return m; -} - -BYTE -mpio_id_valid(BYTE id) -{ - switch(id) - { - case 0xec: /* Samsung */ - case 0x98: /* Toshiba */ - return 1; - default: - ; - } - - return 0; -} - -void -mpio_id2geo(BYTE id, mpio_disk_phy_t *geo) -{ - switch(id) - { - case 0xea: - *geo = MPIO_DISK_GEO_002; - break; - case 0xe3: /* Samsung */ - case 0xe5: /* Toshiba */ - *geo = MPIO_DISK_GEO_004; - break; - case 0xe6: - *geo = MPIO_DISK_GEO_008; - break; - case 0x73: - *geo = MPIO_DISK_GEO_016; - break; - case 0x75: - *geo = MPIO_DISK_GEO_032; - break; - case 0x76: - *geo = MPIO_DISK_GEO_064; - break; - case 0x79: - *geo = MPIO_DISK_GEO_128; - break; - default: - debug("This should never happen!\n"); - exit (1); - } - - return; -} diff --git a/libmpio/smartmedia.h b/libmpio/smartmedia.h deleted file mode 100644 index a7d6b85..0000000 --- a/libmpio/smartmedia.h +++ /dev/null @@ -1,47 +0,0 @@ -/* -*- linux-c -*- */ - -/* - * - * $Id: smartmedia.h,v 1.2 2002/10/26 13:07:43 germeier Exp $ - * - * Library for USB MPIO-* - * - * Markus Germeier (mager@tzi.de) - * - * - * 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. - * - * */ - -#ifndef _MPIO_SMARTMEDIA_H_ -#define _MPIO_SMARTMEDIA_H_ - -#include "defs.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* get our configuration for SmartMedia cards right */ -int mpio_id2mem (BYTE); -BYTE * mpio_id2manufacturer(BYTE); -void mpio_id2geo(BYTE, mpio_disk_phy_t *); -BYTE mpio_id_valid(BYTE); - -#ifdef __cplusplus -} -#endif - -#endif /* _MPIO_SMARTMEDIA_H_ */ diff --git a/libmpio/src/cis.c b/libmpio/src/cis.c new file mode 100644 index 0000000..776959d --- /dev/null +++ b/libmpio/src/cis.c @@ -0,0 +1,81 @@ +/* + * + * $Id: cis.c,v 1.1 2003/04/23 08:34:14 crunchy Exp $ + * + * Library for USB MPIO-* + * + * Markus Germeier (mager@tzi.de) + * + * + * 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 "cis.h" + +/* This data is CIS block (Card Information System) of the SmartMedia + * cards, it can be found here: + * http://www.samsungelectronics.com/semiconductors/flash/technical_data/application_notes/SM_format.pdf (page 8 + 9) + * or on any Smartmedia card + * + * It is not believed to be some kind of trade secret or such, so ... + * ... if we are mistaken, please tell us so. + */ + +char cis_templ[0x80] = { + 0x01, 0x03, 0xd9, 0x01, 0xff, 0x18, 0x02, 0xdf, /* 0x00 */ + 0x01, 0x20, 0x04, 0x00, 0x00, 0x00, 0x00, 0x21, + + 0x02, 0x04, 0x01, 0x22, 0x02, 0x01, 0x01, 0x22, /* 0x10 */ + 0x03, 0x02, 0x04, 0x07, 0x1a, 0x05, 0x01, 0x03, + + 0x00, 0x02, 0x0f, 0x1b, 0x08, 0xc0, 0xc0, 0xa1, /* 0x20 */ + 0x01, 0x55, 0x08, 0x00, 0x20, 0x1b, 0x0a, 0xc1, + + 0x41, 0x99, 0x01, 0x55, 0x64, 0xf0, 0xff, 0xff, /* 0x30 */ + 0x20, 0x1b, 0x0c, 0x82, 0x41, 0x18, 0xea, 0x61, + + 0xf0, 0x01, 0x07, 0xf6, 0x03, 0x01, 0xee, 0x1b, /* 0x40 */ + 0x0c, 0x83, 0x41, 0x18, 0xea, 0x61, 0x70, 0x01, + + 0x07, 0x76, 0x03, 0x01, 0xee, 0x15, 0x14, 0x05, /* 0x50 */ + 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + + 0x00, 0x20, 0x20, 0x20, 0x20, 0x00, 0x30, 0x2e, /* 0x60 */ + 0x30, 0x00, 0xff, 0x14, 0x00, 0xff, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + +}; + +BYTE * +mpio_cis_gen() +{ + BYTE *p; + + p = (BYTE *)malloc(SECTOR_SIZE); + + memset(p, 0, SECTOR_SIZE); + memcpy(p, cis_templ, 0x80); + memcpy(p+0x100, cis_templ, 0x80); + + return p; + +} + + + + diff --git a/libmpio/src/cis.h b/libmpio/src/cis.h new file mode 100644 index 0000000..544d2fa --- /dev/null +++ b/libmpio/src/cis.h @@ -0,0 +1,42 @@ +/* + * + * $Id: cis.h,v 1.1 2003/04/23 08:34:14 crunchy Exp $ + * + * Library for USB MPIO-* + * + * Markus Germeier (mager@tzi.de) + * + * + * 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. + * + * */ + +#ifndef _MPIO_CIS_H_ +#define _MPIO_CIS_H_ + +#include "defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* generate and return a fresh CIS block */ +BYTE *mpio_cis_gen(); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libmpio/src/debug.c b/libmpio/src/debug.c new file mode 100644 index 0000000..5fd5cbe --- /dev/null +++ b/libmpio/src/debug.c @@ -0,0 +1,313 @@ +/* + * debug.c + * + * Authors: Dirk Meyer + * Andreas Büsching + * + * $Id: debug.c,v 1.1 2003/04/23 08:34:14 crunchy Exp $ + */ + +#include "debug.h" + +#include +#include +#include +#include +#include + +#define DCOLOR "_color" +#define DFILE "_file" +#define DSUFFIX "_debug" +#define LEVEL_HEXDUMP 5 + +#define CHECK_FD if (__debug_fd == NULL) return; + +char *__debug_color = NULL; +int __debug_level = 0; +FILE *__debug_fd = NULL; + +void +debug_init(void) { + char *env_var = malloc(strlen(DPACKAGE) + strlen(DFILE) + 1); + const char *env; + + /* check debug output file */ + strcpy(env_var, DPACKAGE); + strcat(env_var, DFILE); + + if ((env = getenv(env_var))) { + if (__debug_fd && fileno(__debug_fd) != -1) { + fclose(__debug_fd); + } + + __debug_fd = fopen(env, "a"); + if (!__debug_fd) { + __debug_fd = stderr; + } + } else { + __debug_fd = stderr; + } + + free(env_var); + + /* check debug level */ + env_var = malloc(strlen(DPACKAGE) + strlen(DSUFFIX) + 1); + strcpy(env_var, DPACKAGE); + strcat(env_var, DSUFFIX); + + if ((env = getenv(env_var))) + if (isdigit(env[0])) + __debug_level = strtol(env, NULL, 10); + else + __debug_level = 1; + else + __debug_level = -1; + + free(env_var); + + /* check debug color */ + env_var = malloc(strlen(DPACKAGE) + strlen(DCOLOR) + 1); + + strcpy(env_var, DPACKAGE); + strcat(env_var, DCOLOR); + + if (__debug_color) free(__debug_color); + __debug_color = NULL; + + if ((env = getenv(env_var))) { + if (env[0] != '\0') { + __debug_color = malloc(4 + strlen(env)); + sprintf(__debug_color, "\033[%sm", env); + } else + __debug_color = malloc(6); + strcpy(__debug_color, "\033[32m"); + } else { + __debug_color = NULL; + } + + free(env_var); +} + +int +debug_file(char *filename) +{ + if (__debug_fd && fileno(__debug_fd) != -1) { + fclose(__debug_fd); + } + + __debug_fd = fopen(filename, "a"); + if (!__debug_fd) { + perror("fopen:"); + __debug_fd = stderr; + return 0; + } + + return 1; +} + +int +debug_level(int level) +{ + int tmp = __debug_level; + + __debug_level = level; + + return tmp; +} + +int +debug_level_get(void) +{ + return __debug_level; +} + + +void +_hexdump (const char *package, const char* file, int line, + const char* function, const char* data, int len) +{ + char buf[17]; + int i; + + CHECK_FD; + + if (_use_debug(LEVEL_HEXDUMP)) { + fprintf (__debug_fd, "%s%s:\033[m %s(%d): %s: data=%p len=%d\n", + __debug_color, package, file, line, function, data, len); + for (i = 0; data != NULL && i < len; i++) { + if (i % 16 == 0) + fprintf(__debug_fd, "\033[30m%s:\033[m %04x: ", package, i); + fprintf(__debug_fd, "%02x ", (unsigned int)(unsigned char)data[i]); + buf[i % 16] = (data[i] >= 32 && data[i] <= 126) ? data[i] : '.'; + buf[i % 16 + 1] = '\0'; + if (i % 4 == 3) fprintf(__debug_fd, " "); + if (i % 16 == 15) fprintf(__debug_fd, "%s\n", buf); + } + if (i % 16 != 0) { + for (; i % 16 != 0; i++) + fprintf (__debug_fd, (i % 4 == 3) ? " " : " "); + fprintf(__debug_fd, "%s\n", buf); + } + } +} + +void +_hexdump_n (const char *package, const int n, const char* file, int line, + const char* function, const char* data, int len) +{ + char buf[17]; + int i; + + CHECK_FD; + + if (_use_debug(n)) { + fprintf (__debug_fd, "%s%s:\033[m %s(%d): %s: data=%p len=%d\n", + __debug_color, package, file, line, function, data, len); + for (i = 0; data != NULL && i < len; i++) { + if (i % 16 == 0) + fprintf(__debug_fd, "\033[30m%s:\033[m %04x: ", package, i); + fprintf(__debug_fd, "%02x ", (unsigned int)(unsigned char)data[i]); + buf[i % 16] = (data[i] >= 32 && data[i] <= 126) ? data[i] : '.'; + buf[i % 16 + 1] = '\0'; + if (i % 4 == 3) fprintf(__debug_fd, " "); + if (i % 16 == 15) fprintf(__debug_fd, "%s\n", buf); + } + if (i % 16 != 0) { + for (; i % 16 != 0; i++) + fprintf (__debug_fd, (i % 4 == 3) ? " " : " "); + fprintf(__debug_fd, "%s\n", buf); + } + } +} + + +void +_hexdump_text (const char *text, + const char *package, const char *file, int line, + const char *function, const char *data, int len) +{ + CHECK_FD; + + if (_use_debug(LEVEL_HEXDUMP)) { + fprintf(__debug_fd, "%s%s: %s(%d): %s: %s\033[m", __debug_color, + package, file, line, function, text); + _hexdump(package, file, line, function, data, len); + } +} + + + +void +_error(const char *package, const char *file, int line, + const char *function, int fatal, const char *format, ...) +{ + char foo[2048]; + va_list ap; + + CHECK_FD; + + va_start(ap, format); + + + vsnprintf(foo, sizeof(foo) - strlen(format) - 1, format, ap); + if (_use_debug(0)) + fprintf(__debug_fd, "\033[31m%s: %s(%d): %s: %s\033[m", + package, file, line, function, foo); + else + fprintf(__debug_fd, "%s: %s(%d): %s: %s", + package, file, line, function, foo); + fflush(__debug_fd); + + if (fatal) { + fprintf(__debug_fd, "\033[31mfatal error -- exit programm\033[m\n"); + exit(1); + } + + va_end(ap); +} + +void +_debug(const char *package, const char *file, int line, + const char *function, const char *format, ...) +{ + char foo[2048]; + va_list ap; + va_start(ap, format); + + CHECK_FD; + + vsnprintf(foo, sizeof(foo) - strlen(format) - 1, format, ap); + + if (_use_debug(0)) { + fprintf(__debug_fd, "%s%s: %s(%d): %s: %s\033[m", + ( __debug_color ? __debug_color : ""), + package, file, line, function, foo); + fflush(__debug_fd); + } + + va_end(ap); +} + +void +_debug_n(const char *package, const int n, const char *file, + int line, const char *function, const char *format, ...) +{ + char foo[2048]; + va_list ap; + va_start(ap, format); + + CHECK_FD; + + vsnprintf(foo, sizeof(foo) - strlen(format) - 1, format, ap); + + if (_use_debug(n)) { + fprintf(__debug_fd, "%s%s: %s(%d): %s: %s\033[m", + ( __debug_color ? __debug_color : ""), + package, file, line, function, foo); + fflush(__debug_fd); + } + + va_end(ap); +} + +void +_octetstr(const char *package, const char *file, int line, + const char *function, const uint8_t *str, + const unsigned int len, const char *what) +{ + CHECK_FD; + + if (_use_debug(LEVEL_HEXDUMP)) { + unsigned int i; + + fprintf(__debug_fd, "%s%s: %s(%d): %s: ", + package, file, function, line, (what?what:"")); + for (i = 0; i < len; i++) { + if (i < (len - 1)) + fprintf(__debug_fd, "%03d.", str [i]); + else + fprintf(__debug_fd, "%03d", str [i]); + } + } +} + +int +_use_debug(int level) +{ + if (__debug_level == -1) return 0; + + CHECK_FD; + + if (level <= __debug_level) { + return 1; + } + + return 0; +} + +/* end of debug.c */ + + + + + diff --git a/libmpio/src/debug.h b/libmpio/src/debug.h new file mode 100644 index 0000000..8f5ff7e --- /dev/null +++ b/libmpio/src/debug.h @@ -0,0 +1,110 @@ +/* + * debug.h + * + * Author: Dirk Meyer + * Andreas Büsching + * + * $Id: debug.h,v 1.1 2003/04/23 08:34:14 crunchy Exp $ + */ + +#ifndef _MPIO_DEBUG_H_ +#define _MPIO_DEBUG_H_ + +// if DPACKAGE is not definied use PACKAGE or "unknown" + +#ifndef DPACKAGE + +#ifdef PACKAGE +#define DPACKAGE PACKAGE +#else +#define DPACKAGE unknown +#endif + +#endif + +#include + +#ifdef sun +#include +#else +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef PBOOL +#define PBOOL(x) (x)?"True":"False" +#endif + +#define UNUSED(x) (x = x) + +#define debugn(n,args...) \ + _debug_n(DPACKAGE, n, __FILE__, __LINE__, __FUNCTION__, args) + +#define debug(args...) \ + _debug(DPACKAGE, __FILE__, __LINE__, __FUNCTION__, args) + +#define debug_error(fatal,args...) \ + _error(DPACKAGE, __FILE__, __LINE__, __FUNCTION__, fatal, args) + +#define hexdump(data,len) \ + _hexdump(DPACKAGE, __FILE__, __LINE__, __FUNCTION__, data, len) + +#define hexdumpn(n,data,len) \ + _hexdump_n(DPACKAGE, n, __FILE__, __LINE__, __FUNCTION__, data, len) + +#define hexdump_text(text,data,len) \ + _hexdump_text(text, DPACKAGE, __FILE__, __LINE__, __FUNCTION__, data, len) + +#define octetstrdump(data,len) \ + _octetstr(DPACKAGE, __FILE__, __LINE__, __FUNCTION__, data, len) + +#define ipadr_dump(data,len,text) \ + _octetstr(DPACKAGE, __FILE__, __LINE__, __FUNCTION__, data, len, text) + +#define use_debug() \ + use_debug(DPACKAGE) + + +#define with_special_debug(what) \ + _use_debug(DPACKAGE, what) + +void debug_init(void); +int debug_file(char *filename); +int debug_level(int level); +int debug_level_get(void); + +void _debug(const char *package, const char* file, int line, + const char* function, const char *format, ...); + +void _debug_n(const char *package, const int n, const char* file, + int line, const char* function, const char *format, ...); + +void _hexdump (const char *package, const char* file, int line, + const char* function, const char* data, int len); + +void _hexdump_n (const char *package, const int n, const char* file, int line, + const char* function, const char* data, int len); + +void _hexdump_text (const char *text, + const char *package, const char* file, int line, + const char* function, const char* data, int len); + +void _error(const char *package, const char* file, int line, + const char* function, int fatal, const char *format, ...); + +void _octetstr(const char *package, const char* file, int line, + const char* function, const uint8_t *str, + const unsigned int len, const char *what); + +int _use_debug(int level); + +#ifdef __cplusplus +} +#endif + +#endif /* _MPIO_DEBUG_H_ */ + +/* end of debug.h */ diff --git a/libmpio/src/defs.h b/libmpio/src/defs.h new file mode 100644 index 0000000..f676e23 --- /dev/null +++ b/libmpio/src/defs.h @@ -0,0 +1,334 @@ +/* -*- linux-c -*- */ + +/* + * $Id: defs.h,v 1.1 2003/04/23 08:34:14 crunchy Exp $ + * + * Library for USB MPIO-* + * + * Markus Germeier (mager@tzi.de) + * + * uses code from mpio_stat.c by + * Yuji Touya (salmoon@users.sourceforge.net) + * + * + * 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. + * + * */ + +#ifndef _MPIO_DEFS_H_ +#define _MPIO_DEFS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef unsigned char BYTE; +typedef unsigned short WORD; +typedef unsigned int DWORD; + +/* Memory selection */ +typedef enum { MPIO_INTERNAL_MEM = 0x01, + MPIO_EXTERNAL_MEM = 0x10 } mpio_mem_t; + +/* model type */ +typedef enum { MPIO_MODEL_DME = 0x00, + MPIO_MODEL_DMG = 0x01, + MPIO_MODEL_DMG_PLUS = 0x02, + MPIO_MODEL_DMB = 0x03, + MPIO_MODEL_DMB_PLUS = 0x04, + MPIO_MODEL_DMK = 0x05, + MPIO_MODEL_FD100 = 0x06, + MPIO_MODEL_FL100 = 0x07, + MPIO_MODEL_FY100 = 0x08, + MPIO_MODEL_UNKNOWN = 0x09 } mpio_model_t; + +/* USB commands */ +typedef enum { GET_VERSION = 0x01, + GET_BLOCK = 0x02, + PUT_SECTOR = 0x03, + DEL_BLOCK = 0x04, + GET_SECTOR = 0x06, + GET_SPARE_AREA = 0x07, + PUT_BLOCK = 0x08, + MODIFY_FIRMWARE = 0xa0 } mpio_cmd_t; + +/* file types on internal memory */ +/* found in the code of salmoon, are these needed? -mager */ +typedef enum { FTYPE_CHAN = 0x00, + FTYPE_MUSIC = 0x01, + FTYPE_CONF = 'C', + FTYPE_FONT = 'F', + FTYPE_OTHER = 'H', + FTYPE_MEMO = 'M', + FTYPE_WAV = 'V', + FTYPE_ENTRY = 'R', + FTYPE_DIR = 'D', + FTYPE_PLAIN = '-'} mpio_filetype_t; + +/* fixed filenames */ +#define MPIO_CONFIG_FILE "CONFIG.DAT" +#define MPIO_CHANNEL_FILE "FMCONFIG.DAT" +#define MPIO_MPIO_RECORD "MPIO RECORD" + +/* type of callback functions */ +typedef BYTE (*mpio_callback_t)(int, int) ; +typedef BYTE (*mpio_callback_init_t)(mpio_mem_t, int, int) ; + +/* zone lookup table */ +#define MPIO_ZONE_MAX 8 /* 8* 16MB = 128MB */ +#define MPIO_ZONE_PBLOCKS 1024 /* physical blocks per zone */ +#define MPIO_ZONE_LBLOCKS 1000 /* logical blocks per zone */ +typedef DWORD mpio_zonetable_t[MPIO_ZONE_MAX][MPIO_ZONE_PBLOCKS]; + +#define MPIO_BLOCK_FREE 0xffff +#define MPIO_BLOCK_DEFECT 0xffee +#define MPIO_BLOCK_CIS 0xaaaa +#define MPIO_BLOCK_NOT_FOUND 0xcccccccc + +/* filenames */ +#define MPIO_FILENAME_LEN 129 +typedef BYTE mpio_filename_t[MPIO_FILENAME_LEN]; + +#ifndef NULL +#define NULL 0 +#endif + +#define MPIO_DEVICE "/dev/usb/mpio" +#define MPIO_CHARSET "ISO-8859-15" + +#define MPIO_ID3_FORMAT "%p - %t" + +#define SECTOR_SIZE 0x200 +#define SECTOR_ECC 0x040 +#define SECTOR_TRANS (SECTOR_SIZE + SECTOR_ECC) + +#define BLOCK_SECTORS 0x20 /* 0x10 8MB Smartmedia :salmoon */ +#define BLOCK_SIZE (SECTOR_SIZE * BLOCK_SECTORS) +#define BLOCK_TRANS (BLOCK_SIZE + (SECTOR_ECC * BLOCK_SECTORS)) + +#define DIR_NUM 0x10 +#define DIR_SIZE (SECTOR_SIZE*DIR_NUM) +#define DIR_ENTRY_SIZE 0x20 + +#define SMALL_MEM 0x02 + +#define CMD_SIZE 0x40 + +#define INFO_LINE 129 + +/* error codes */ +typedef struct { + int id; + char *msg; +} mpio_error_t; + +#define MPIO_OK 0 +#define MPIO_ERR_FILE_NOT_FOUND -1 +#define MPIO_ERR_NOT_ENOUGH_SPACE -2 +#define MPIO_ERR_FILE_EXISTS -3 +#define MPIO_ERR_FAT_ERROR -4 +#define MPIO_ERR_READING_FILE -5 +#define MPIO_ERR_PERMISSION_DENIED -6 +#define MPIO_ERR_WRITING_FILE -7 +#define MPIO_ERR_DIR_TOO_LONG -8 +#define MPIO_ERR_DIR_NOT_FOUND -9 +#define MPIO_ERR_DIR_NOT_A_DIR -10 +#define MPIO_ERR_DIR_NAME_ERROR -11 +#define MPIO_ERR_DIR_NOT_EMPTY -12 +#define MPIO_ERR_DEVICE_NOT_READY -13 +#define MPIO_ERR_OUT_OF_MEMORY -14 +#define MPIO_ERR_INTERNAL -15 +/* internal errors, occur when UI has errors! */ +#define MPIO_ERR_INT_STRING_INVALID -101 + +/* get formatted information, about the MPIO player */ + +typedef struct { + BYTE firmware_id[INFO_LINE]; + BYTE firmware_version[INFO_LINE]; + BYTE firmware_date[INFO_LINE]; + + BYTE model[INFO_LINE]; + + BYTE mem_internal[INFO_LINE]; + BYTE mem_external[INFO_LINE]; + +} mpio_info_t; + +/* view of the MPIO firmware */ +typedef struct { + /* everything we get from GET_VERSION */ + BYTE id[12]; + BYTE major[3]; + BYTE minor[3]; + BYTE year[5]; + BYTE month[3]; + BYTE day[3]; +} mpio_firmware_t; + +/* */ +typedef struct { + DWORD NumCylinder; + DWORD NumHead; + DWORD NumSector; + DWORD SumSector; +} mpio_disk_phy_t; + +/* */ + +struct mpio_directory_tx { + BYTE name[INFO_LINE]; + BYTE dir[BLOCK_SIZE]; + + BYTE *dentry; + + struct mpio_directory_tx *prev; + struct mpio_directory_tx *next; + +}; +typedef struct mpio_directory_tx mpio_directory_t; + + +/* view of a SmartMedia(tm) card */ +typedef struct { + BYTE id; + BYTE manufacturer; + WORD size; /* MB */ + BYTE chips; /* this is the hack for + MPIO internal representation, because + there might be up to four chips involved */ + + /* only needed for external SmartMedia cards */ + mpio_disk_phy_t geo; + + BYTE cis[SECTOR_SIZE]; + BYTE mbr[SECTOR_SIZE]; /* Master Boot Record */ + BYTE pbr[SECTOR_SIZE]; /* Partition Boot Record */ + + int pbr_offset; /* sector offset for the PBR */ + int fat_offset; /* sector offset for the FAT */ + int dir_offset; + + /* these are needed for internal and external cards */ + int max_cluster; /* # of clusters actually available */ + int fat_size; /* # sectors for FAT */ + int fat_nums; /* # of FATs */ + BYTE * fat; /* *real FAT (like in block allocation :-) */ + + /* needed for directory support */ + mpio_directory_t *root; /* root directory */ + mpio_directory_t *cdir; /* current directory */ + + /* how many physical blocks are available + * for internal memory is this value equal to max_cluster + */ + int max_blocks; + BYTE * spare; + + /* lookup table for phys.<->log. block mapping */ + mpio_zonetable_t zonetable; + +} mpio_smartmedia_t; + +/* health status of a memory "card" */ +typedef struct { + WORD total; /* total blocks on "card" */ + WORD spare; /* (available spare blocks */ + WORD broken; /* broken blocks */ +} mpio_health_single_t; + +typedef struct { + BYTE num; /* number of chips or zones */ + /* internal: max 4 chips + * external: max 8 zones (128MB) -> max 8 */ + mpio_health_single_t data[8]; +} mpio_health_t; + +/* view of the MPIO-* */ +typedef struct { + BYTE version[CMD_SIZE]; + + int fd; + BYTE *charset; /* charset used for filename conversion */ + + BYTE id3; /* enable/disable ID3 rewriting support */ + BYTE id3_format[INFO_LINE]; + BYTE id3_temp[INFO_LINE]; + + mpio_firmware_t firmware; + + mpio_model_t model; + + mpio_smartmedia_t internal; + mpio_smartmedia_t external; +} mpio_t; + +typedef struct { + mpio_t *m; + BYTE mem; /* internal/external memory */ + + DWORD entry; /* number of FAT entry */ + + /* internal */ + BYTE i_index; /* file index of file to store */ + BYTE i_fat[16]; /* internal FAT entry */ + + /* external */ + DWORD e_sector; /* logical startsector of cluster */ + + /* mapping to HW (== block address) */ + DWORD hw_address; /* 3 bytes block addressing + 1 byte chip */ + +} mpio_fatentry_t; + + +/* these are copied from: + * http://www.linuxhq.com/kernel/v2.4/doc/filesystems/vfat.txt.html + * + */ + +typedef struct { // Short 8.3 names + unsigned char name[8]; // file name + unsigned char ext[3]; // file extension + unsigned char attr; // attribute byte + unsigned char lcase; // Case for base and extension + unsigned char ctime_ms; // Creation time, milliseconds + unsigned char ctime[2]; // Creation time + unsigned char cdate[2]; // Creation date + unsigned char adate[2]; // Last access date + unsigned char reserved[2]; // reserved values (ignored) + unsigned char time[2]; // time stamp + unsigned char date[2]; // date stamp + unsigned char start[2]; // starting cluster number + unsigned char size[4]; // size of the file +} mpio_dir_entry_t; + +typedef struct { // Up to 13 characters of a long name + unsigned char id; // sequence number for slot + unsigned char name0_4[10]; // first 5 characters in name + unsigned char attr; // attribute byte + unsigned char reserved; // always 0 + unsigned char alias_checksum; // checksum for 8.3 alias + unsigned char name5_10[12]; // 6 more characters in name + unsigned char start[2]; // starting cluster number + unsigned char name11_12[4]; // last 2 characters in name +} mpio_dir_slot_t; + +#ifdef __cplusplus +} +#endif + +#endif /* _MPIO_DEFS_H_ */ + diff --git a/libmpio/src/directory.c b/libmpio/src/directory.c new file mode 100644 index 0000000..fe8464c --- /dev/null +++ b/libmpio/src/directory.c @@ -0,0 +1,1318 @@ +/* + * + * $Id: directory.c,v 1.1 2003/04/23 08:34:14 crunchy Exp $ + * + * Library for USB MPIO-* + * + * Markus Germeier (mager@tzi.de) + * + * + * 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 +#include + +#include "debug.h" +#include "io.h" +#include "mpio.h" +#include "directory.h" +#include + +#define UNICODE "UNICODELITTLE" + +/* the following function is copied from the linux kernel v2.4.18 + * file:/usr/src/linux/fs/fat/misc.c + * it was written by Werner Almesberger and Igor Zhbanov + * and is believed to be GPL + */ + +/* Linear day numbers of the respective 1sts in non-leap years. */ + +static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 }; + /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */ + +/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */ + +int date_dos2unix(unsigned short time,unsigned short date) +{ + int month,year,secs; + struct timezone sys_tz; + struct timeval tv; + + gettimeofday(&tv, &sys_tz); + + /* first subtract and mask after that... Otherwise, if + date == 0, bad things happen */ + month = ((date >> 5) - 1) & 15; + year = date >> 9; + secs = (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400* + ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 && + month < 2 ? 1 : 0)+3653); + /* days since 1.1.70 plus 80's leap day */ + secs += sys_tz.tz_minuteswest*60; + return secs; +} + +/* + * charset for filename encoding/converting + */ +BYTE * +mpio_charset_get(mpio_t *m) +{ + return strdup(m->charset); +} + +BYTE +mpio_charset_set(mpio_t *m, BYTE *charset) +{ + iconv_t ic; + int r = 1; + + ic = iconv_open(UNICODE, charset); + if (ic < 0) + r=0; + iconv_close(ic); + + ic = iconv_open(charset, UNICODE); + if (ic < 0) + r=0; + iconv_close(ic); + + if (r) + { + debugn(2, "setting new charset to: \"%s\"\n", charset); + free(m->charset); + m->charset=strdup(charset); + } else { + debugn(2, "could not set charset to: \"%s\"\n", charset); + } + + return r; +} + +int +mpio_directory_init(mpio_t *m, mpio_mem_t mem, mpio_directory_t *dir, + WORD self, WORD parent) +{ + mpio_dir_entry_t *dentry; + + memset(dir->dir, 0, BLOCK_SIZE); + memset(dir->dir, 0x20, 11); + memset(dir->dir+0x20, 0x20, 11); + + dentry = (mpio_dir_entry_t *)dir->dir; + + strncpy(dentry->name, ". ", 8); + strncpy(dentry->ext, " ", 3); + dentry->start[0] = self & 0xff; + dentry->start[1] = self / 0x100; + dentry->attr = 0x10; + + dentry++; + strncpy(dentry->name, ".. ", 8); + strncpy(dentry->ext, " ", 3); + dentry->start[0] = parent & 0xff; + dentry->start[1] = parent / 0x100; + dentry->attr = 0x10; + + hexdumpn(2, dir->dir, 64); + + return 0; +} + + +int +mpio_directory_read(mpio_t *m, mpio_mem_t mem, mpio_directory_t *dir) +{ + mpio_fatentry_t *f = 0; + + f = mpio_dentry_get_startcluster(m, mem, dir->dentry); + + if (!f) + { + debug("something bad has happened here!"); + exit (-1); + } + + mpio_io_block_read(m, mem, f, dir->dir); + + hexdumpn(5, dir->dir, DIR_SIZE); + + return 0; +} + +BYTE +mpio_directory_is_empty(mpio_t *m, mpio_mem_t mem, mpio_directory_t *dir) +{ + mpio_dir_entry_t *dentry; + BYTE r; + + dentry = (mpio_dir_entry_t *)dir->dir; + dentry += 2; + + r = MPIO_OK; + if (dentry->name[0] != 0x00) + r = !r; + + return r; +} + + +int +mpio_directory_write(mpio_t *m, mpio_mem_t mem, mpio_directory_t *dir) +{ + mpio_fatentry_t *f = 0; + + f = mpio_dentry_get_startcluster(m, mem, dir->dentry); + if (!f) + { + debug("something bad has happened here!"); + exit (-1); + } + + if (mem==MPIO_INTERNAL_MEM) + { + f->i_fat[0x01]= f->i_index; + if (m->model >= MPIO_MODEL_FD100) + f->i_fat[0x0e] = f->i_index; + + /* only one block needed for directory */ + f->i_fat[0x02]=0; + f->i_fat[0x03]=1; + + /* set type to directory */ + f->i_fat[0x06] = FTYPE_ENTRY; + + hexdumpn(2, f->i_fat, 16); + } + + mpio_io_block_delete(m, mem, f); + mpio_io_block_write(m, mem, f, dir->dir); + + return 0; +} + +/* directory operations */ +BYTE * +mpio_directory_open(mpio_t *m, mpio_mem_t mem) +{ + BYTE *out; + if (mem == MPIO_EXTERNAL_MEM) { + if (m->external.id) { + out = m->external.cdir->dir; + } else { + return NULL; + } + } else { + out = m->internal.cdir->dir; + } + + if (out[0] == 0x00) + { + debugn(3, "directory is empty\n"); + return NULL; + } + + debugn(3, "first dentry: %08x\n", out); + + return out; +} + +int +mpio_directory_make(mpio_t *m, mpio_mem_t mem, BYTE *dir) +{ + mpio_smartmedia_t *sm; + mpio_directory_t *new; + mpio_fatentry_t *f, *current; + WORD self, parent; + struct tm tt; + time_t curr; + + if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; + if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; + + if ((strcmp(dir, "..") == 0) || + (strcmp(dir, ".") == 0)) + { + debugn(2, "directory name not allowed: %s\n", dir); + return MPIO_ERR_DIR_NAME_ERROR; + } + + /* find free sector */ + f = mpio_fatentry_find_free(m, mem, FTYPE_ENTRY); + if (!f) + { + debug("could not free cluster for file!\n"); + return (MPIO_ERR_FAT_ERROR); + } else { + self=f->entry; + } + + /* find file-id for internal memory */ + if (mem==MPIO_INTERNAL_MEM) + { + f->i_index=mpio_fat_internal_find_fileindex(m); + debugn(2, "fileindex: %02x\n", f->i_index); + f->i_fat[0x01]= f->i_index; + if (m->model >= MPIO_MODEL_FD100) + f->i_fat[0x0e] = f->i_index; + self = f->i_index; + + /* only one block needed for directory */ + f->i_fat[0x02]=0; + f->i_fat[0x03]=1; + hexdumpn(2, f->i_fat, 16); + } + + if (sm->cdir == sm->root) + { + parent=0; + } else { + current = mpio_dentry_get_startcluster(m, mem, sm->cdir->dentry); + if (mem==MPIO_INTERNAL_MEM) + { + parent = current->i_index; + } else { + parent = current->entry; + } + } + + + new = malloc(sizeof(mpio_directory_t)); + mpio_directory_init(m, mem, new, self, parent); + + mpio_fatentry_set_eof(m ,mem, f); + mpio_io_block_write(m, mem, f, new->dir); + time(&curr); + tt = * localtime(&curr); + mpio_dentry_put(m, mem, + dir, strlen(dir), + mktime(&tt), + 0, self, 0x10); + + free(new); + + return MPIO_OK; +} + +int +mpio_directory_cd(mpio_t *m, mpio_mem_t mem, BYTE *dir) +{ + mpio_smartmedia_t *sm; + BYTE *p; + BYTE month, day, hour, minute, type; + BYTE fname[100]; + WORD year; + DWORD fsize; + int i, size; + BYTE pwd[INFO_LINE]; + mpio_directory_t *old, *new; + + if (strcmp(dir, ".")==0) + return MPIO_OK; + + if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; + if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; + + if (strcmp(dir, "..") == 0) + { + if (sm->cdir->prev) + { + old = sm->cdir; + sm->cdir = sm->cdir->prev; + sm->cdir->next = NULL; + free(old); + } + + return MPIO_OK; + } + + mpio_directory_pwd(m, mem, pwd); + + if ((strlen(pwd) + strlen(dir) + 2) > INFO_LINE) + { + debugn(2, "directory name gets to long!\n"); + return MPIO_ERR_DIR_TOO_LONG; + } + + + p = mpio_dentry_find_name(m, mem, dir); + + /* second try */ + if (!p) + p = mpio_dentry_find_name_8_3(m, mem, dir); + + if (!p) + { + debugn(2, "could not find directory: %s\n", dir); + return MPIO_ERR_DIR_NOT_FOUND; + } + + mpio_dentry_get(m, mem, p, + fname, 100, + &year, &month, &day, + &hour, &minute, &fsize, + &type); + + if (type != FTYPE_DIR) + { + debugn(2, "this is not a directory: %s\n", dir); + return MPIO_ERR_DIR_NOT_A_DIR; + } + + new = malloc(sizeof(mpio_directory_t)); + strcpy(new->name, dir); + new->next = NULL; + new->prev = sm->cdir; + new->dentry = p; + sm->cdir->next = new; + sm->cdir = new; + + mpio_directory_pwd(m, mem, pwd); + + if (strcmp(dir, "/") != 0) + { + /* read new directory */ + size=mpio_directory_read(m, mem, sm->cdir); + } + + return MPIO_OK; + +} + + +void +mpio_directory_pwd(mpio_t *m, mpio_mem_t mem, BYTE pwd[INFO_LINE]) +{ + mpio_smartmedia_t *sm; + mpio_directory_t *d; + + if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; + if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; + + d = sm->root->next; + pwd[0] = 0; + + if (!d) + strcat(pwd, "/"); + + while (d) + { + strcat(pwd, "/"); + debugn(2, "name: %s\n", d->name); + strcat(pwd, d->name); + d = d->next; + } + + return; +} + +mpio_dir_entry_t * +mpio_dentry_filename_write(mpio_t *m, mpio_mem_t mem, BYTE *p, + BYTE *filename, int filename_size) +{ + BYTE *unicode = 0; + BYTE *back, *fback; + BYTE *fname = 0; + iconv_t ic; + int in = 0, out = 0; + int fin = 0, fout = 0; + int count = 0; + BYTE index; + BYTE f_8_3[13]; + mpio_dir_slot_t *slot; + mpio_dir_entry_t *dentry; + int i, j, points; + + /* generate vfat filename in UNICODE */ + ic = iconv_open(UNICODE, m->charset); + fin = in = filename_size + 1; + fout = out = filename_size * 2 + 2 + 26; + fname = malloc(in); + fback = fname; + unicode = malloc(out); + back = unicode; + + memset(fname, 0, in); + snprintf(fname, in, "%s", filename); + memset(unicode, 0xff, out); + iconv(ic, (char **)&fback, &fin, (char **)&back, &fout); + iconv_close(ic); + hexdump(fname, in); + hexdump(unicode, out); + + back = unicode; + + count = filename_size / 13; + if (filename_size % 13) + count++; + + slot = (mpio_dir_slot_t *)p; + + index = 0x40 + count; + while (count > 0) { + mpio_dentry_copy_to_slot(back + ((count - 1) * 26), slot); + hexdump((char *)back + ((count - 1) * 26), 0x20); + slot->id = index; + slot->attr = 0x0f; + slot->reserved = 0x00; + slot->start[0] = 0x00; + slot->start[1] = 0x00; + /* FIXME: */ + slot->alias_checksum = 0x00; // checksum for 8.3 alias + + hexdump((char *)slot, 0x20); + + slot++; + count--; + index = count; + } + +/* memcpy(p, m->internal.dir+0x220, 0x20); */ + +/* p+=0x20; */ + dentry = (mpio_dir_entry_t *)slot; + + /* find uniq 8.3 filename */ + memset(f_8_3, 0x20, 12); + f_8_3[8]='.'; + f_8_3[12]=0x00; + + i=0; + points=0; + /* count points to later find the correct file extension */ + while (i<(strlen(filename))) + { + if (filename[i] == '.') + points++; + i++; + } + + /* if we do not find any points we set the value ridiculously high, + then everything falls into place */ + if (!points) + points=1024*1024; + + i=j=0; + while ((j<8) && (points) && (i<(strlen(filename)))) + { + if (filename[i] == '.') + { + points--; + } else { + if (filename[i]!=' ') { + f_8_3[j] = toupper(filename[i]); + j++; + } + } + i++; + } + + j=i; + while((points) && (j<(strlen(filename)))) + { + if (filename[j] == '.') + points--; + j++; + } + + i=9; + while ((i<12) && (j<(strlen(filename)))) + { + f_8_3[i] = toupper(filename[j]); + i++; + j++; + } + + /* This seems like a special case to me! */ + if (strcmp(MPIO_MPIO_RECORD, filename)==0) + { + f_8_3[6]='~'; + f_8_3[7]='0'; + } + + if (mpio_dentry_find_name_8_3(m, mem, f_8_3)) + { + f_8_3[6]='~'; + f_8_3[7]='1'; + } + + while(mpio_dentry_find_name_8_3(m, mem, f_8_3)) + f_8_3[7]++; + + +/* memcpy(dentry->name,"AAAAAAAA",8); */ +/* memcpy(dentry->ext,"MP3",3); */ + +/* hexdumpn(0, f_8_3, 13); */ + + memcpy(dentry->name, f_8_3, 8); + memcpy(dentry->ext, f_8_3+9, 3); + + free(unicode); + free(fname); + + return dentry; +} + + +int +mpio_dentry_get_size(mpio_t *m, mpio_mem_t mem, BYTE *buffer) +{ + mpio_dir_entry_t *dentry; + + if (!buffer) + return -1; + + UNUSED(m); + + dentry = (mpio_dir_entry_t *)buffer; + + if ((dentry->name[0] & 0x40) && + (dentry->attr == 0x0f) && + (dentry->start[0] == 0x00) && + (dentry->start[1] == 0x00)) { + dentry++; + while ((dentry->attr == 0x0f) && + (dentry->start[0] == 0x00) && + (dentry->start[1] == 0x00)) { + /* this/these are vfat slots */ + dentry++; + } + } + dentry++; + + return(((BYTE *)dentry) - buffer); +} + +BYTE* +mpio_dentry_next(mpio_t *m, mpio_mem_t mem, BYTE *buffer) +{ + int size; + BYTE *out; + + size = mpio_dentry_get_size(m, mem, buffer); + + if (size<=0) + return NULL; + + out = buffer + size; + + if (*out == 0x00) + { + debugn(3, "no more entries\n"); + return NULL; + } + + debugn(3, "next dentry: %08x\n", out); + + return out; +} + +int +mpio_dentry_get_raw(mpio_t *m, mpio_mem_t mem, BYTE *dentry, + BYTE *buffer, int bufsize) +{ + int size; + + size = mpio_dentry_get_size(m, mem, buffer); + debugn(3, "dentry size is: 0x%02x\n", size); + + if (size < 0) + return size; + + if (size > bufsize) + return -2; + + memcpy(buffer, dentry, size); + + return size; +} + +void +mpio_dentry_copy_from_slot(BYTE *buffer, mpio_dir_slot_t *slot) +{ + memcpy(buffer, slot->name0_4, 10); + memcpy(buffer + 10, slot->name5_10, 12); + memcpy(buffer + 22, slot->name11_12, 4); +} + +void +mpio_dentry_copy_to_slot(BYTE *buffer, mpio_dir_slot_t *slot) +{ + memcpy(slot->name0_4, buffer, 10); + memcpy(slot->name5_10, buffer + 10, 12); + memcpy(slot->name11_12, buffer + 22, 4); +} + +int +mpio_dentry_get(mpio_t *m, mpio_mem_t mem, BYTE *buffer, + BYTE *filename, int filename_size, + WORD *year, BYTE *month, BYTE *day, + BYTE *hour, BYTE *minute, DWORD *fsize, BYTE *type) +{ + BYTE filename_8_3[13]; + + return mpio_dentry_get_real(m, mem, buffer, filename, filename_size, + filename_8_3, + year, month, day, hour, minute, fsize, type); +} + +/* TODO: please clean me up !!! */ +int +mpio_dentry_get_real(mpio_t *m, mpio_mem_t mem, BYTE *buffer, + BYTE *filename, int filename_size, + BYTE *filename_8_3, + WORD *year, BYTE *month, BYTE *day, + BYTE *hour, BYTE *minute, DWORD *fsize, + BYTE *type) +{ + int date, time; + int vfat = 0; + int num_slots = 0; + int slots = 0; + int in = 0, out = 0, iconv_return; + mpio_dir_entry_t *dentry; + mpio_dir_slot_t *slot; + BYTE *unicode = 0; + BYTE *uc; + BYTE *fname = 0; + iconv_t ic; + int dsize, i; + + if (buffer == NULL) + return -1; + + dentry = (mpio_dir_entry_t *)buffer; + + if ((dentry->name[0] & 0x40) && + (dentry->attr == 0x0f) && + (dentry->start[0] == 0x00) && + (dentry->start[1] == 0x00)) + { + dsize = mpio_dentry_get_size(m, mem, buffer); + debugn(3, "dentry size is: 0x%02x\n", dsize); + hexdump(buffer, dsize); + num_slots = (dsize / 0x20) - 1; + slots = num_slots - 1; + dentry++; + vfat++; + in = num_slots * 26; + out = num_slots * 13; + unicode = malloc(in + 2); + memset(unicode, 0x00, (in+2)); + uc = unicode; + fname = filename; + slot = (mpio_dir_slot_t *)buffer; + mpio_dentry_copy_from_slot(unicode + (26 * slots), slot); + slots--; + + while ((dentry->attr == 0x0f) && + (dentry->start[0] == 0x00) && + (dentry->start[1] == 0x00)) + { + /* this/these are vfat slots */ + slot = (mpio_dir_slot_t *)dentry; + mpio_dentry_copy_from_slot((unicode + (26 * slots)), slot); + dentry++; + slots--; + } + } + + if (vfat) + { + ic = iconv_open(m->charset, UNICODE); + memset(fname, 0, filename_size); + hexdumpn(4, unicode, in+2); + debugn(4, "before iconv: in: %2d - out: %2d\n", in, out); + iconv_return = iconv(ic, (char **)&uc, &in, (char **)&fname, &out); + debugn(4, "after iconv: in: %2d - out: %2d (return: %d)\n", in, out, + iconv_return); + hexdumpn(4, filename, (num_slots*13)-out); + iconv_close(ic); + } + free(unicode); + + memcpy(filename_8_3, dentry->name, 8); + i=8; + while(filename_8_3[i-1]==' ') + i--; + filename_8_3[i++] = '.'; + memcpy(filename_8_3 + i, dentry->ext, 3); + i+=3; + while(filename_8_3[i-1]==' ') + i--; + filename_8_3[i] = 0; + hexdumpn(4, filename_8_3, 13); + + if (!vfat) + { + if (filename_size >= 12) + { + snprintf(filename, 13, "%s", filename_8_3); + /* UGLY !! */ + if (((strncmp(dentry->name, ". ", 8)==0) && + (strncmp(dentry->ext, " ", 3) == 0))) + filename[1]=0; + if (((strncmp(dentry->name, ".. ", 8)==0) && + (strncmp(dentry->ext, " ", 3) == 0))) + filename[2]=0; + } else { + snprintf(filename, filename_size, "%s", "ERROR"); + } + } + + date = (dentry->date[1] * 0x100) + dentry->date[0]; + *year = date / 512 + 1980; + *month = (date / 32) & 0xf; + *day = date & 0x1f; + + time = (dentry->time[1] * 0x100) + dentry->time[0]; + *hour = time / 2048; + *minute= (time / 32) & 0x3f; + + *fsize = dentry->size[3]; + *fsize *= 0x100; + *fsize += dentry->size[2]; + *fsize *= 0x100; + *fsize += dentry->size[1]; + *fsize *= 0x100; + *fsize += dentry->size[0]; + + if (dentry->attr & 0x10) { + /* is this a directory? */ + *type = FTYPE_DIR; + } else { + *type = FTYPE_PLAIN; + } + + return(((BYTE *)dentry) - buffer); +} + +/* read "size" sectors of fat into the provided buffer */ +int +mpio_rootdir_read (mpio_t *m, mpio_mem_t mem) +{ + mpio_smartmedia_t *sm; + BYTE recvbuff[SECTOR_SIZE]; + int i; + + if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; + if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; + + for (i = 0; i < DIR_NUM; i++) { + if (mpio_io_sector_read(m, mem, (sm->dir_offset + i), recvbuff)) + return 1; + + memcpy(sm->root->dir + (i * SECTOR_SIZE), recvbuff, SECTOR_SIZE); + } + + return (0); +} + +int +mpio_rootdir_clear (mpio_t *m, mpio_mem_t mem) +{ + mpio_smartmedia_t *sm; + + if (mem == MPIO_INTERNAL_MEM) sm=&m->internal; + if (mem == MPIO_EXTERNAL_MEM) sm=&m->external; + + memset(sm->root->dir, 0x00, DIR_SIZE); + + return 0; +} + +BYTE +mpio_dentry_is_dir(mpio_t *m, mpio_mem_t mem, BYTE *p) +{ + int s; + mpio_dir_entry_t *dentry; + BYTE r; + + s = mpio_dentry_get_size(m, mem, p); + s -= DIR_ENTRY_SIZE ; + + dentry = (mpio_dir_entry_t *)p; + + while (s != 0) { + dentry++; + s -= DIR_ENTRY_SIZE ; + } + + if (dentry->attr & 0x10) { + r = MPIO_OK; + } else { + r= !MPIO_OK; + } + + return r; +} + +int +mpio_dentry_get_filesize(mpio_t *m, mpio_mem_t mem, BYTE *p) +{ + int s; + int fsize; + mpio_dir_entry_t *dentry; + + s = mpio_dentry_get_size(m, mem, p); + s -= DIR_ENTRY_SIZE ; + + dentry = (mpio_dir_entry_t *)p; + + while (s != 0) { + dentry++; + s -= DIR_ENTRY_SIZE ; + } + + if (dentry->attr & 0x10) { + fsize = BLOCK_SIZE; + } else { + fsize = dentry->size[3]; + fsize *= 0x100; + fsize += dentry->size[2]; + fsize *= 0x100; + fsize += dentry->size[1]; + fsize *= 0x100; + fsize += dentry->size[0]; + } + + return fsize; +} + +long +mpio_dentry_get_time(mpio_t *m, mpio_mem_t mem, BYTE *p) +{ + int s; + mpio_dir_entry_t *dentry; + + s = mpio_dentry_get_size(m, mem, p); + s -= DIR_ENTRY_SIZE ; + + dentry = (mpio_dir_entry_t *)p; + + while (s != 0) { + dentry++; + s -= DIR_ENTRY_SIZE ; + } + + + return date_dos2unix((dentry->time[0]+dentry->time[1]*0x100), + (dentry->date[0]+dentry->date[1]*0x100)); +} + + + +mpio_fatentry_t * +mpio_dentry_get_startcluster(mpio_t *m, mpio_mem_t mem, BYTE *p) +{ + int s; + DWORD cluster; + BYTE i_index; + mpio_dir_slot_t *dentry; + mpio_fatentry_t *new; + + s = mpio_dentry_get_size(m, mem, p); + s -= DIR_ENTRY_SIZE ; + + dentry = (mpio_dir_slot_t *)p; + + while (s != 0) { + dentry++; + s -= DIR_ENTRY_SIZE ; + } + + cluster = dentry->start[1] * 0x100 + dentry->start[0]; + + if (mem == MPIO_INTERNAL_MEM) + { + i_index=dentry->start[0]; + cluster = mpio_fat_internal_find_startsector(m, cluster); + } + if (cluster < 0) + return NULL; + + new = mpio_fatentry_new(m, mem, cluster, FTYPE_MUSIC); + + if (mem == MPIO_INTERNAL_MEM) + { + new->entry=cluster; + new->i_index=i_index; + mpio_fatentry_entry2hw(m, new); + } + + debugn(2,"i_index=0x%02x\n", new->i_index); + + return new; +} + +int +mpio_dentry_put(mpio_t *m, mpio_mem_t mem, + BYTE *filename, int filename_size, + time_t date, DWORD fsize, WORD ssector, BYTE attr) +{ + BYTE *p; + mpio_dir_entry_t *dentry; + + /* read and copied code from mtools-3.9.8/directory.c + * to make this one right + */ + struct tm *now; + time_t date2 = date; + unsigned char hour, min_hi, min_low, sec; + unsigned char year, month_hi, month_low, day; + + + p = mpio_directory_open(m, mem); + if (p) { + while (*p != 0x00) + p += 0x20; + } else { + if (mem == MPIO_EXTERNAL_MEM) + p = m->external.cdir->dir; + if (mem == MPIO_INTERNAL_MEM) + p = m->internal.cdir->dir; + } + + dentry = mpio_dentry_filename_write(m, mem, p, filename, filename_size); + + dentry->attr = attr; + dentry->lcase = 0x00; + + /* read and copied code from mtools-3.9.8/directory.c + * to make this one right + */ + now = localtime(&date2); + dentry->ctime_ms = 0; + hour = now->tm_hour << 3; + min_hi = now->tm_min >> 3; + min_low = now->tm_min << 5; + sec = now->tm_sec / 2; + dentry->ctime[1] = dentry->time[1] = hour + min_hi; + dentry->ctime[0] = dentry->time[0] = min_low + sec; + year = (now->tm_year - 80) << 1; + month_hi = (now->tm_mon + 1) >> 3; + month_low = (now->tm_mon + 1) << 5; + day = now->tm_mday; + dentry -> adate[1] = dentry->cdate[1] = dentry->date[1] = year + month_hi; + dentry -> adate[0] = dentry->cdate[0] = dentry->date[0] = month_low + day; + + dentry->size[0] = fsize & 0xff; + dentry->size[1] = (fsize / 0x100) & 0xff; + dentry->size[2] = (fsize / 0x10000) & 0xff; + dentry->size[3] = (fsize / 0x1000000) & 0xff; + dentry->start[0] = ssector & 0xff; + dentry->start[1] = ssector / 0x100; + + /* what do we want to return? */ + return 0; +} + +BYTE * +mpio_dentry_find_name_8_3(mpio_t *m, BYTE mem, BYTE *filename) +{ + BYTE *p; + BYTE bdummy; + WORD wdummy; + BYTE fname[129]; + BYTE fname_8_3[13]; + DWORD ddummy; + BYTE *found = 0; + int i, j, len; + + p = mpio_directory_open(m, mem); + while ((p) && (!found)) { + mpio_dentry_get_real (m, mem, p, + fname, 128, + fname_8_3, + &wdummy, &bdummy, &bdummy, + &bdummy, &bdummy, &ddummy, &bdummy); + if ((strcmp(fname_8_3, filename) == 0) && + (strcmp(filename,fname_8_3) == 0)) { + found = p; + p = NULL; + } + + p = mpio_dentry_next(m, mem, p); + } + + return found; +} + +BYTE * +mpio_dentry_find_name(mpio_t *m, BYTE mem, BYTE *filename) +{ + BYTE *p; + BYTE bdummy; + WORD wdummy; + BYTE fname[129]; + DWORD ddummy; + BYTE *found = 0; + + p = mpio_directory_open(m, mem); + while ((p) && (!found)) { + mpio_dentry_get (m, mem, p, + fname, 128, + &wdummy, &bdummy, &bdummy, + &bdummy, &bdummy, &ddummy, &bdummy); + if ((strcmp(fname,filename) == 0) && (strcmp(filename,fname) == 0)) { + found = p; + p = NULL; + } + + p = mpio_dentry_next(m, mem, p); + } + + return found; +} + + +int +mpio_dentry_delete(mpio_t *m, BYTE mem, BYTE *filename) +{ + mpio_smartmedia_t *sm; + BYTE *start; + int size; + BYTE tmp[DIR_SIZE]; + + if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; + if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; + + start = mpio_dentry_find_name(m, mem, filename); + + /* second try */ + if (!start) + start = mpio_dentry_find_name_8_3(m, mem, filename); + + if (!start) { + debugn(2, "could not find file: %s\n", filename); + return 0; + } + + size = mpio_dentry_get_size(m, mem, start); + + if (size <= 0) { + debug("fatal error in mpio_dentry_delete\n"); + return 0; + } + + debugn(5, "size: %2x\n", size); + + /* clear new buffer */ + memset(tmp, 0, DIR_SIZE); + /* copy before delete */ + if (start != sm->cdir->dir) + memcpy(tmp, sm->cdir->dir, (start - (sm->cdir->dir))); + /* copy after delete */ + memcpy(tmp + (start - (sm->cdir->dir)), (start + size), + (sm->cdir->dir + DIR_SIZE - (start + size))); + + memcpy(sm->cdir->dir, tmp, DIR_SIZE); + + return 0; +} + +void +mpio_dentry_move(mpio_t *m,mpio_mem_t mem,BYTE *m_file,BYTE *a_file) { + mpio_smartmedia_t *sm; + + BYTE *t0,*t1,*t2,*t3; + + int s0,s1,s2,s3; + int m_file_s,a_file_s; + BYTE tmp[DIR_SIZE]; + BYTE *b_file; + + if (mem == MPIO_INTERNAL_MEM) + sm = &m->internal; + + if (mem == MPIO_EXTERNAL_MEM) + sm = &m->external; + + if (m_file == a_file) + return; + + m_file_s = mpio_dentry_get_size(m, mem, m_file); + a_file_s = mpio_dentry_get_size(m, mem, a_file); + + // -- we determine the 'befor' file. The start of the region which needs to be moved down + // -- if a_file == NULL this is the start of the directory. + + if(a_file==NULL) { + b_file = sm->cdir->dir; + } else { + b_file = a_file + a_file_s; + } + + if(b_file == m_file) { + return; + } + + /** We disect the whole directory in four pieces. + in different ways according to the direction + the directoy entry is moved (up or down). + */ + + if(m_file > b_file) { + fprintf(stderr,"U "); + t0 = sm->cdir->dir; + s0 = b_file - sm->cdir->dir; + + t1 = m_file; + s1 = m_file_s; + + t2 = b_file; + s2 = m_file - b_file; + + t3 = m_file + m_file_s; + s3 = DIR_SIZE - (m_file-sm->cdir->dir) - m_file_s; + } else { + fprintf(stderr,"D "); + t0 = sm->cdir->dir; + s0 = m_file - sm->cdir->dir; + + t1 = m_file + m_file_s; + s1 = a_file + a_file_s - (m_file + m_file_s); + + t2 = m_file; + s2 = m_file_s; + + t3 = b_file; + s3 = DIR_SIZE - (b_file - sm->cdir->dir); + } + + if(s0) { + memcpy(tmp,t0,s0); + } + + if(s1) { + memcpy(tmp + s0 , t1 , s1 ); + } + + if(s2) { + memcpy(tmp + s0 + s1, t2, s2); + } + + if(s3) { + memcpy(tmp + s0 + s1 + s2, t3, s3); + } + + fprintf(stderr," -- t0=%ld, s0=%d, t1=%ld, s1=%d, t2=%ld, s2=%d, t3=%ld, s3=%d; sum=%d, DIRSIZE=%d\n", + (long)t0,s0,(long)t1,s1,(long)t2,s2,(long)t3,s3,s0+s1+s2+s3,DIR_SIZE); + + memcpy(sm->cdir->dir, tmp, DIR_SIZE); +} + +void +mpio_dentry_switch(mpio_t *m, mpio_mem_t mem, BYTE *file1, BYTE *file2) +{ + mpio_smartmedia_t *sm; + BYTE *p1, *p2; + BYTE *current; + int size1 , size2; + BYTE tmp[DIR_SIZE]; + + if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; + if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; + + if (file1 == file2) + return; + + if (file1cdir->dir) + { + memcpy(current, sm->cdir->dir, p1 - sm->cdir->dir); + current += (p1 - sm->cdir->dir); + } + /* the second file*/ + memcpy(current, p2, size2); + current += size2; + /* between the files */ + memcpy(current, p1+size1, (p2-p1-size1)); + current += (p2-p1-size1); + /* the first file */ + memcpy(current, p1, size1); + current += size1; + /* and the rest */ + memcpy(current, p2+size2, (sm->cdir->dir+DIR_SIZE-p2-size2)); + + /* really update the directory */ + memcpy(sm->cdir->dir, tmp, DIR_SIZE); + + return; +} + +void +mpio_dentry_rename(mpio_t *m, mpio_mem_t mem, BYTE *p, BYTE *newfilename) +{ + mpio_smartmedia_t *sm; + BYTE *current; + int size1 , size2, offset, offset_d1, offset_d2; + BYTE tmp[DIR_SIZE]; + + if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; + if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; + + current = sm->cdir->dir; + + size1 = mpio_dentry_get_size(m, mem, p) / 0x20; + size2 = (strlen(newfilename) / 13) + 1; + if ((strlen(newfilename) % 13)) + size2++; + + debugn(2, "size1: %d size2: %d\n", size1, size2); + + /* we want to copy the last dentry to the right location + * so we avoid reading and writing the same information + */ + size1--; /* kludge so we can do compares without worry */ + size2--; + + memcpy(tmp, current, DIR_SIZE); + offset = p - current; + offset_d1 = offset + (size1 * 0x20); + offset_d2 = offset + (size2 * 0x20); + + if (size2>size1) { + /* new filename needs at least one slot more than the old one */ + memcpy(current+offset_d2, tmp+offset_d1, (DIR_SIZE-offset_d1)); + } + + if (size2> offset) & 0x01 ); +} + +int +mpio_ecc_256_gen(BYTE *data, BYTE *ecc) +{ + BYTE p1, p1_; + BYTE p2, p2_; + BYTE p4, p4_; + + BYTE p08, p08_; + BYTE p16, p16_; + BYTE p32, p32_; + BYTE p64, p64_; + + BYTE p0128, p0128_; + BYTE p0256, p0256_; + BYTE p0512, p0512_; + BYTE p1024, p1024_; + + int i, j; + + /* init */ + p1=p1_=0; + p2=p2_=0; + p4=p4_=0; + + p08=p08_=0; + p16=p16_=0; + p32=p32_=0; + p64=p64_=0; + + p0128=p0128_=0; + p0256=p0256_=0; + p0512=p0512_=0; + p1024=p1024_=0; + + /* vertical */ + for (i=0; i<256; i++) { + + /* p1, p1_ */ + p1 ^= (get_bit(data[i], 7) ^ + get_bit(data[i], 5) ^ + get_bit(data[i], 3) ^ + get_bit(data[i], 1)); + p1_^= (get_bit(data[i], 6) ^ + get_bit(data[i], 4) ^ + get_bit(data[i], 2) ^ + get_bit(data[i], 0)); + + /* p2, p2_ */ + p2 ^= (get_bit(data[i], 7) ^ + get_bit(data[i], 6) ^ + get_bit(data[i], 3) ^ + get_bit(data[i], 2)); + p2_^= (get_bit(data[i], 5) ^ + get_bit(data[i], 4) ^ + get_bit(data[i], 1) ^ + get_bit(data[i], 0)); + + /* p4, p4_ */ + p4 ^= (get_bit(data[i], 7) ^ + get_bit(data[i], 6) ^ + get_bit(data[i], 5) ^ + get_bit(data[i], 4)); + p4_^= (get_bit(data[i], 3) ^ + get_bit(data[i], 2) ^ + get_bit(data[i], 1) ^ + get_bit(data[i], 0)); + } + + /* horizontal */ + for (i=0; i<8; i++) { + + for (j=0; j<256; j++) { + + /* p08, p08_ */ + if ((j & 0x01) == 0) + p08_^= get_bit(data[j], i); + if ((j & 0x01) == 1) + p08 ^= get_bit(data[j], i); + + /* p16, p16_ */ + if (((j/2) & 0x01) == 0) + p16_^= get_bit(data[j], i); + if (((j/2) & 0x01) == 1) + p16^= get_bit(data[j], i); + + /* p32, p32_ */ + if (((j/4) & 0x01) == 0) + p32_^= get_bit(data[j], i); + if (((j/4) & 0x01) == 1) + p32^= get_bit(data[j], i); + + /* p64, p64_ */ + if (((j/8) & 0x01) == 0) + p64_^= get_bit(data[j], i); + if (((j/8) & 0x01) == 1) + p64^= get_bit(data[j], i); + + + /* p0128, p0128_ */ + if (((j/16) & 0x01) == 0) + p0128_^= get_bit(data[j], i); + if (((j/16) & 0x01) == 1) + p0128 ^= get_bit(data[j], i); + + /* p0256, p0256_ */ + if (((j/32) & 0x01) == 0) + p0256_^= get_bit(data[j], i); + if (((j/32) & 0x01) == 1) + p0256^= get_bit(data[j], i); + + /* p0512, p0512_ */ + if (((j/64) & 0x01) == 0) + p0512_^= get_bit(data[j], i); + if (((j/64) & 0x01) == 1) + p0512^= get_bit(data[j], i); + + /* p1024, p1024_ */ + if (((j/128) & 0x01) == 0) + p1024_^= get_bit(data[j], i); + if (((j/128) & 0x01) == 1) + p1024^= get_bit(data[j], i); + + } + } + + ecc[0]=~((p64 << 7) | (p64_ << 6) | + (p32 << 5) | (p32_ << 4) | + (p16 << 3) | (p16_ << 2) | + (p08 << 1) | (p08_ << 0)); + + ecc[1]=~((p1024 << 7) | (p1024_ << 6) | + (p0512 << 5) | (p0512_ << 4) | + (p0256 << 3) | (p0256_ << 2) | + (p0128 << 1) | (p0128_ << 0)); + + ecc[2]=~((p4 << 7) | (p4_ << 6) | + (p2 << 5) | (p2_ << 4) | + (p1 << 3) | (p1_ << 2)); + + return 0; +} + + +int +mpio_ecc_256_check(BYTE *data, BYTE *ecc) +{ + BYTE own_ecc[3]; + BYTE check[3]; + BYTE c; + BYTE line, col; + + int v, i; + + mpio_ecc_256_gen(data, own_ecc); + if ((own_ecc[0]^ecc[0])| + (own_ecc[1]^ecc[1])| + (own_ecc[2]^ecc[2])) { + debugn(2, "ECC %2x %2x %2x vs. %2x %2x %2x\n", + ecc[0], ecc[1], ecc[2], own_ecc[0], own_ecc[1], own_ecc[2]); + check[0] = (ecc[0] ^ own_ecc[0]); + check[1] = (ecc[1] ^ own_ecc[1]); + check[2] = (ecc[2] ^ own_ecc[2]); + + v=1; + for(i=0; i<4; i++) + { + if (!((get_bit(check[1], i*2) ^ + (get_bit(check[1], i*2+1))))) + v=0; + if (!((get_bit(check[0], i*2) ^ + (get_bit(check[0], i*2+1))))) + v=0; + } + for(i=1; i<4; i++) + { + if (!((get_bit(check[2], i*2) ^ + (get_bit(check[2], i*2+1))))) + v=0; + } + + if (v) { + debug("correctable error detected ... fixing the bit\n"); + line = get_bit(check[1], 7) * 128 + + get_bit(check[1], 5) * 64 + + get_bit(check[1], 3) * 32 + + get_bit(check[1], 1) * 16 + + get_bit(check[0], 7) * 8 + + get_bit(check[0], 5) * 4 + + get_bit(check[0], 3) * 2 + + get_bit(check[0], 1); + col = get_bit(check[2], 7) * 4 + + get_bit(check[2], 5) * 2 + + get_bit(check[2], 3); + debug ("error in line: %d , col %d\n", line, col); + debug ("defect byte is: %02x\n", data[line]); + data[line] ^= ( 1 << col); + debug ("fixed byte is: %02x\n", data[line]); + } else { + debug("uncorrectable error detected. Sorry you lose!\n"); + return 1; + } + } + + return 0; +} + + + + diff --git a/libmpio/src/ecc.h b/libmpio/src/ecc.h new file mode 100644 index 0000000..55ca297 --- /dev/null +++ b/libmpio/src/ecc.h @@ -0,0 +1,44 @@ +/* + * + * $Id: ecc.h,v 1.1 2003/04/23 08:34:15 crunchy Exp $ + * + * Library for USB MPIO-* + * + * Markus Germeier (mager@tzi.de) + * + * + * 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. + * + * */ + +#ifndef _MPIO_ECC_H_ +#define _MPIO_ECC_H_ + +#include "defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* 256 Bytes Data, 3 Byte ECC to generate */ +int mpio_ecc_256_gen(BYTE *, BYTE *); +/* 256 Bytes Data, 3 Bytes ECC to check and possibly correct */ +int mpio_ecc_256_check(BYTE *, BYTE*); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libmpio/src/fat.c b/libmpio/src/fat.c new file mode 100644 index 0000000..27974cd --- /dev/null +++ b/libmpio/src/fat.c @@ -0,0 +1,1039 @@ +/* + * + * $Id: fat.c,v 1.1 2003/04/23 08:34:15 crunchy Exp $ + * + * Library for USB MPIO-* + * + * Markus Germeier (mager@tzi.de) + * + * + * 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 "fat.h" +#include "io.h" +#include "debug.h" + +#include +#include + +/* I'm lazy so I hard code all the values */ + +BYTE mpio_part_016[0x10] = { + 0x80, 0x02, 0x0a, 0x00, 0x01, 0x03, 0x50, 0xf3, + 0x29, 0x00, 0x00, 0x00, 0xd7, 0x7c, 0x00, 0x00 +}; +BYTE mpio_part_032[0x10] = { + 0x80, 0x02, 0x04, 0x00, 0x01, 0x07, 0x50, 0xf3, + 0x23, 0x00, 0x00, 0x00, 0xdd, 0xf9, 0x00, 0x00 +}; +BYTE mpio_part_064[0x10] = { + 0x80, 0x01, 0x18, 0x00, 0x01, 0x07, 0x60, 0xf3, + 0x37, 0x00, 0x00, 0x00, 0xc9, 0xf3, 0x01, 0x00 +}; +BYTE mpio_part_128[0x10] = { + 0x80, 0x01, 0x10, 0x00, 0x06, 0x0f, 0x60, 0xf3, + 0x2f, 0x00, 0x00, 0x00, 0xd1, 0xe7, 0x03, 0x00 +}; + +/* ------------------------- */ + +BYTE mpio_pbr_head[0x10] = { + 0xe9, 0x00, 0x00, 0x4d, 0x53, 0x44, 0x4f, 0x53, + 0x35, 0x2e, 0x30, 0x00, 0x02, 0x20, 0x01, 0x00 +}; +BYTE mpio_pbr_016[0x13] = { + 0x02, 0x00, 0x01, 0xd7, 0x7c, 0xf8, 0x03, 0x00, + 0x10, 0x00, 0x04, 0x00, 0x29, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00 +}; +BYTE mpio_pbr_032[0x13] = { + 0x02, 0x00, 0x01, 0xdd, 0xf9, 0xf8, 0x06, 0x00, + 0x10, 0x00, 0x08, 0x00, 0x23, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00 +}; +BYTE mpio_pbr_064[0x13] = { + 0x02, 0x00, 0x01, 0x00, 0x00, 0xf8, 0x0c, 0x00, + 0x20, 0x00, 0x08, 0x00, 0x37, 0x00, 0x00, 0x00, + 0xc9, 0xf3, 0x01 +}; +BYTE mpio_pbr_128[0x13] = { + 0x02, 0x00, 0x01, 0x00, 0x00, 0xf8, 0x20, 0x00, + 0x20, 0x00, 0x10, 0x00, 0x2f, 0x00, 0x00, 0x00, + 0xd1, 0xe7, 0x03 +}; + +BYTE * +mpio_mbr_gen(BYTE size) +{ + BYTE *p; + + p = (BYTE *)malloc(SECTOR_SIZE); + memset(p, 0, SECTOR_SIZE); + + /* MBR signature */ + p[0x1fe] = 0x55; + p[0x1ff] = 0xaa; + + /* frist boot partition */ + switch(size) + { + case 16: + memcpy(p+0x1be, mpio_part_016, 0x10); + break; + case 32: + memcpy(p+0x1be, mpio_part_032, 0x10); + break; + case 64: + memcpy(p+0x1be, mpio_part_064, 0x10); + break; + case 128: + memcpy(p+0x1be, mpio_part_128, 0x10); + break; + default: + debug("This should never happen! (%d)\n", size); + exit(-1); + } + + /* all other partitions are set to zero */ + + return p; +} + +BYTE * +mpio_pbr_gen(BYTE size) +{ + BYTE *p; + + p = (BYTE *)malloc(SECTOR_SIZE); + memset(p, 0, SECTOR_SIZE); + + /* MBR signature */ + p[0x1fe] = 0x55; + p[0x1ff] = 0xaa; + + memcpy(p, mpio_pbr_head, 0x10); + /* BIOS parameter etc. */ + switch(size) + { + case 16: + memcpy(p+0x10, mpio_pbr_016, 0x13); + break; + case 32: + memcpy(p+0x10, mpio_pbr_032, 0x13); + break; + case 64: + memcpy(p+0x10, mpio_pbr_064, 0x13); + break; + case 128: + memcpy(p+0x10, mpio_pbr_128, 0x13); + break; + default: + debug("This should never happen! (%d)\n", size); + exit(-1); + } + + /* FAT id */ + if (size >=128) { + strcpy(p+0x36, "FAT16"); + } else { + strcpy(p+0x36, "FAT12"); + } + + return p; +} + +int +mpio_mbr_eval(mpio_smartmedia_t *sm) +{ + BYTE *pe; /* partition entry */ + int sector, head, cylinder; + + if ((sm->mbr[0x1fe] != 0x55) || (sm->mbr[0x1ff] != 0xaa)) + { + debug("This is not the MBR!\n"); + return 1; + } + + /* always use the first partition */ + /* we probably don't need to support others */ + pe = sm->mbr + 0x1be; + + head = (int)(*(pe+0x01) & 0xff); + sector = (int)(*(pe+0x02) & 0x3f); + cylinder = (int)((*(pe+0x02) >> 6) * 0x100 + *(pe + 0x03)); + + sm->pbr_offset=(cylinder * sm->geo.NumHead + head ) * + sm->geo.NumSector + sector - 1; + + return 0; + +} + + +int +mpio_pbr_eval(mpio_smartmedia_t *sm) +{ + BYTE *bpb; /* BIOS Parameter Block */ + int total_sector; + long temp; + + if ((sm->pbr[0x1fe] != 0x55) || (sm->pbr[0x1ff] != 0xaa)) + { + debug("This is not the PBR!\n"); + return 1; + } + + if (strncmp((sm->pbr+0x36),"FAT", 3) != 0) + { + debug("Did not find an FAT signature, *not* good!\n"); + return 2; + } + + bpb = sm->pbr + 0x0b; + + total_sector = (*(sm->pbr+0x14) * 0x100 + *(sm->pbr + 0x13)); + if (!total_sector) + total_sector = (*(sm->pbr+0x23) * 0x1000000 + + *(sm->pbr+0x22) * 0x10000 + + *(sm->pbr+0x21) * 0x100 + + *(sm->pbr+0x20)); + + /* 128 MB need 2 Bytes instead of 1.5 */ + if (sm->size != 128) + { + temp = ((total_sector / 0x20 * 0x03 / 0x02 / 0x200) + 0x01); + } else { + temp = ((total_sector / 0x20 * 0x02 / 0x200) + 0x01); + } + + sm->fat_offset = sm->pbr_offset + 0x01; + sm->fat_size = temp; + sm->fat_nums = *(sm->pbr + 0x10); + sm->dir_offset = sm->pbr_offset + 0x01 + temp * 2; + sm->max_cluster = (total_sector / BLOCK_SECTORS); + /* fix max clusters */ + temp*=2; + while (temp>=0x10) + { + sm->max_cluster--; + temp-=BLOCK_SECTORS; + } + + return 0; +} + + +void +mpio_fatentry_hw2entry(mpio_t *m, mpio_fatentry_t *f) +{ + mpio_smartmedia_t *sm; + BYTE chip, t; + DWORD value; + + if (f->mem == MPIO_INTERNAL_MEM) + { + sm = &m->internal; + + if (f->hw_address == 0xffffffff) + return ; + + value = f->hw_address; + t = value >> 24; + chip = 0; + + while(t/=2) + chip++; + + value &= 0xffffff; + value /= 0x20; + value += chip * (sm->max_cluster / sm->chips); + + f->entry = value; + + return; + } + + debug("This should never happen!\n"); + exit(-1); + + return; +} + + +void +mpio_fatentry_entry2hw(mpio_t *m, mpio_fatentry_t *f) +{ + mpio_smartmedia_t *sm; + DWORD cluster; + BYTE chip; + + if (f->mem == MPIO_INTERNAL_MEM) + { + sm = &m->internal; + + chip = f->entry / (sm->max_cluster / sm->chips); + cluster = f->entry - ((sm->max_cluster / sm->chips) * chip); + cluster *= 0x20; + cluster += 0x01000000 * (1 << chip); + + f->hw_address=cluster; + + return; + } + + debug("This should never happen!\n"); + exit(-1); + + return; +} + + + +int +mpio_bootblocks_read (mpio_t *m, mpio_mem_t mem) +{ + mpio_smartmedia_t *sm=0; + + int error; + + /* this should not be needed for internal memory, but ... */ + if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; + if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; + if (!sm) + return 1; + + /* in case the external mem is defective we need this here! */ + sm->fat=0; + sm->fat_size=0; + sm->fat_nums=0; + + /* TODO: check a few things more, just to be sure */ + + /* read CIS (just in case it might me usefull) */ + if (mpio_io_sector_read(m, mem, MPIO_BLOCK_CIS, sm->cis)) + { + debug("error reading CIS\n"); + return 1; + } + + /* read MBR */ + /* the MBR is always located @ logical block 0, sector 0! */ + if (mpio_io_sector_read(m, mem, 0, sm->mbr)) + { + debug("error reading MBR\n"); + return 1; + } + + if (error=mpio_mbr_eval(sm)) + { + debug("problem with the MBR (#%d), so I won't try to access the card any" + "further.\n", error); + return 1; + } + + /* read PBR */ + if (mpio_io_sector_read(m, mem, sm->pbr_offset, sm->pbr)) + { + debug("error reading PBR\n"); + return 1; + } + + if (error=mpio_pbr_eval(sm)) + { + debug("problem with the PBR (#%d), so I won't try to access the card any" + "further.\n", error); + return 1; + } + + return 0; +} + +mpio_fatentry_t * +mpio_fatentry_new(mpio_t *m, mpio_mem_t mem, DWORD sector, BYTE ftype) +{ + mpio_smartmedia_t *sm; + mpio_fatentry_t *new; + + new = malloc (sizeof(mpio_fatentry_t)); + + if (new) + { + new->m = m; + new->mem = mem; + new->entry = sector; + + /* init FAT entry */ + memset(new->i_fat, 0xff, 0x10); + new->i_fat[0x00] = 0xaa; /* start of file */ + new->i_fat[0x06] = ftype; + new->i_fat[0x0b] = 0x00; + new->i_fat[0x0c] = 0x00; + new->i_fat[0x0d] = 0x00; + if (m->model >= MPIO_MODEL_FD100) { + /* 0x0e is a copy of the file index number */ + new->i_fat[0x0f] = 0x00; + } else { + new->i_fat[0x0e] = 'P'; + new->i_fat[0x0f] = 'C'; + } + } + + if (mem == MPIO_INTERNAL_MEM) + mpio_fatentry_entry2hw(m, new); + + return new; +} + +int +mpio_fatentry_plus_plus(mpio_fatentry_t *f) +{ + f->entry++; + + if (f->mem == MPIO_INTERNAL_MEM) { + if (f->entry >= f->m->internal.max_cluster) + { + f->entry--; + mpio_fatentry_entry2hw(f->m, f); + return 0; + } + mpio_fatentry_entry2hw(f->m, f); + } + + if (f->mem == MPIO_EXTERNAL_MEM) { + if (f->entry > f->m->external.max_cluster) + { + f->entry--; + return 0; + } + } + + return 1; +} + + +/* read "fat_size" sectors of fat into the provided buffer */ +int +mpio_fat_read (mpio_t *m, mpio_mem_t mem, + mpio_callback_init_t progress_callback) +{ + mpio_smartmedia_t *sm; + BYTE recvbuff[SECTOR_SIZE]; + int i; + + if (mem == MPIO_INTERNAL_MEM) + { + sm = &m->internal; + if (mpio_io_spare_read(m, mem, 0, sm->size, 0, sm->fat, + (sm->fat_size * SECTOR_SIZE), progress_callback)) + return 1; + return 0; + } + + if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; + + if (!sm) + return 1; + + for (i = 0; i < sm->fat_size; i++) { + if (mpio_io_sector_read(m, mem, (sm->fat_offset + i), recvbuff)) + return 1; + + memcpy(sm->fat + (i * SECTOR_SIZE), recvbuff, SECTOR_SIZE); + } + + return (0); +} + +int +mpio_fatentry_free(mpio_t *m, mpio_mem_t mem, mpio_fatentry_t *f ) +{ + int e,i ; + mpio_smartmedia_t *sm; + + if (mem == MPIO_INTERNAL_MEM) { + sm = &m->internal; + e = f->entry * 0x10; + + /* be more strict to avoid writing + * to defective blocks! + */ + i=0; + while (i<0x10) + { + if (sm->fat[e+i] != 0xff) + return 0; + i++; + } + return 1; + } + + if (mem == MPIO_EXTERNAL_MEM) { + sm = &m->internal; + if (mpio_fatentry_read(m, mem, f) == 0) + return 1; + } + + return 0; +} + +DWORD +mpio_fatentry_read(mpio_t *m, mpio_mem_t mem, mpio_fatentry_t *f ) +{ + mpio_smartmedia_t *sm; + int e; + int v; + + if (mem == MPIO_INTERNAL_MEM) { + sm = &m->internal; + e = f->entry * 0x10; + if (mpio_fatentry_is_defect(m, mem, f)) + return 0xffffffff; + + /* this is a special system file! */ + if((sm->fat[e+6] != FTYPE_MUSIC) && + (sm->fat[e+7] == 0xff) && + (sm->fat[e+8] == 0x00) && + (sm->fat[e+9] == 0xff) && + (sm->fat[e+10] == 0xff)) + return 0xffffffff; + /* this is a special system file! */ +/* this is not correct!! */ +/* if (sm->fat[e+6] == FTYPE_CONF) */ +/* return 0xffffffff; */ + /* this is a special system file! */ + if((sm->fat[e+6] != FTYPE_MUSIC) && + (sm->fat[e+0x0b] == 0xff) && + (sm->fat[e+0x0c] == 0xff) && + (sm->fat[e+0x0d] == 0xff)) + return 0xffffffff; + + if((sm->fat[e+7] == 0xff) && + (sm->fat[e+8] == 0xff) && + (sm->fat[e+9] == 0xff) && + (sm->fat[e+10] == 0xff)) + return 0xffffffff; + + v = sm->fat[e+7] * 0x1000000 + + sm->fat[e+8] * 0x10000 + + sm->fat[e+9] * 0x100 + + sm->fat[e+10]; + + return v; + } + + if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; + + if (!sm->fat) + { + debug ("error, no space for FAT allocated!\n"); + return 0; + } + + + if (sm->size == 128) { + /* 2 Byte per entry */ + e = f->entry * 2; + v = sm->fat[e + 1] * 0x100 + sm->fat[e]; + } else { + /* 1.5 Byte per entry */ + /* Nibble order: x321 */ + e = (f->entry * 3 / 2); +/* printf("mager: byte (%d/%d)\n", e, e+1); */ + if ((f->entry & 0x01) == 0) { + /* LLxH */ + /* 21x3 */ + v = (sm->fat[e + 1] & 0x0f) * 0x100 + sm->fat[e]; + } else { + /* 1x32 */ + v = (sm->fat[e + 1] * 0x10) + (sm->fat[e] >> 4); + } + } + + return v; +} + +int +mpio_fatentry_write(mpio_t *m, mpio_mem_t mem, mpio_fatentry_t *f, WORD value) +{ + mpio_smartmedia_t *sm; + int e; + BYTE backup; + + if (mem == MPIO_INTERNAL_MEM) + { + debug("This should not be used for internal memory!\n"); + exit(-1); + } + + if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; + + if (sm->size == 128) + { + /* 2 Byte per entry */ + e = f->entry * 2; + sm->fat[e] = value & 0xff; + sm->fat[e + 1] = (value >> 8 ) & 0xff; + } else { + /* 1.5 Byte per entry */ + e = (f->entry * 3 / 2); + if ((f->entry & 0x01) == 0) { + /* 21x3 */ + sm->fat[e] = value & 0xff; + backup = sm->fat[e + 1] & 0xf0; + sm->fat[e + 1] = backup | (( value / 0x100 ) & 0x0f); + } else { + /* 1x32 */ + sm->fat[e + 1] = (value / 0x10) & 0xff; + backup = sm->fat[e] & 0x0f; + sm->fat[e] = backup | ( (value * 0x10) & 0xf0 ); + } + } + + return 0; +} + +int +mpio_fat_internal_find_startsector(mpio_t *m, BYTE start) +{ + mpio_fatentry_t *f; + mpio_smartmedia_t *sm = &m->internal; + int found=-1; + + f = mpio_fatentry_new(m, MPIO_INTERNAL_MEM, 0, FTYPE_MUSIC); + + while(mpio_fatentry_plus_plus(f)) + { + if ((sm->fat[f->entry * 0x10] == 0xaa) && + (sm->fat[f->entry * 0x10 + 1] == start)) + found=f->entry; + } + + free(f); + + return found; +} + +BYTE +mpio_fat_internal_find_fileindex(mpio_t *m) +{ + mpio_fatentry_t *f; + mpio_smartmedia_t *sm = &m->internal; + BYTE index[256]; + BYTE found; /* hmm, ... */ + + memset(index, 1, 256); + + f = mpio_fatentry_new(m, MPIO_INTERNAL_MEM, 0, FTYPE_MUSIC); + while(mpio_fatentry_plus_plus(f)) + { + if (sm->fat[f->entry * 0x10 + 1] != 0xff) + index[sm->fat[f->entry * 0x10 + 1]] = 0; + } + free(f); + + found=6; + while((found<256) && (!index[found])) + found++; + + if (found==256) + { + debug("Oops, did not find a new fileindex!\n" + "This should never happen, aborting now!, Sorry!\n"); + exit(-1); + } + + return found; +} + + +int +mpio_fat_free_clusters(mpio_t *m, mpio_mem_t mem) +{ + mpio_smartmedia_t *sm; + mpio_fatentry_t *f; + int i; + int e = 0; + int fsize; + + if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; + if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; + + if (sm->fat) + { + f = mpio_fatentry_new(m, mem, 0, FTYPE_MUSIC); + do + { + if (mpio_fatentry_free(m, mem, f)) + e++; + } while (mpio_fatentry_plus_plus(f)); + free(f); + } else { + f = 0; + } + + + return (e * 16); +} + +mpio_fatentry_t * +mpio_fatentry_find_free(mpio_t *m, mpio_mem_t mem, BYTE ftype) +{ + mpio_fatentry_t *f; + + f = mpio_fatentry_new(m, mem, 1, ftype); + + while(mpio_fatentry_plus_plus(f)) + { + if (mpio_fatentry_free(m, mem, f)) + return f; + } + + free(f); + + return NULL; +} + +int +mpio_fatentry_next_free(mpio_t *m, mpio_mem_t mem, mpio_fatentry_t *f) +{ + mpio_fatentry_t backup; + + memcpy(&backup, f, sizeof(mpio_fatentry_t)); + + while(mpio_fatentry_plus_plus(f)) + { + if (mpio_fatentry_free(m, mem, f)) + { + if (mem == MPIO_INTERNAL_MEM) + f->i_fat[0x00] = 0xee; + return 1; + } + } + + /* no free entry found, restore entry */ + memcpy(f, &backup, sizeof(mpio_fatentry_t)); + + return 0; +} + +int +mpio_fatentry_next_entry(mpio_t *m, mpio_mem_t mem, mpio_fatentry_t *f) +{ + mpio_smartmedia_t *sm; + DWORD value; + DWORD endvalue; + + value = mpio_fatentry_read(m, mem, f); + + if (value == 0xaaaaaaaa) + return -1; + + if (mem == MPIO_INTERNAL_MEM) + { + sm = &m->internal; + f->hw_address = value; + + mpio_fatentry_hw2entry(m, f); + + endvalue = 0xffffffff; + } + + + if (mem == MPIO_EXTERNAL_MEM) + { + sm = &m->external; + f->entry = value; + + if (sm->size==128) + { + endvalue = 0xfff8; + } else { + endvalue = 0xff8; + } + } + + if (value >= endvalue) + return 0; + + return 1; +} + + +int +mpio_fat_clear(mpio_t *m, mpio_mem_t mem) +{ + mpio_smartmedia_t *sm; + mpio_fatentry_t *f; + + if (mem == MPIO_INTERNAL_MEM) { + sm = &m->internal; + + f = mpio_fatentry_new(m, mem, 1, FTYPE_MUSIC); + do { + mpio_fatentry_set_free(m, mem, f) ; + } while(mpio_fatentry_plus_plus(f)); + free(f); + } + + if (mem == MPIO_EXTERNAL_MEM) { + sm = &m->external; + memset(sm->fat, 0x00, (sm->fat_size * SECTOR_SIZE)); + sm->fat[0] = 0xf8; + sm->fat[1] = 0xff; + sm->fat[2] = 0xff; + /* for FAT 16 */ + if (sm->size == 128) + sm->fat[3] = 0xff; + } + + return 0; +} + +/* + * This function acutally writes both, + * the FAT _and_ the root directory + * + */ + +int +mpio_fat_write(mpio_t *m, mpio_mem_t mem) +{ + mpio_smartmedia_t *sm; + mpio_fatentry_t *f; + BYTE dummy[BLOCK_SIZE]; + WORD i; + DWORD block; + + if (mem == MPIO_INTERNAL_MEM) { + sm = &m->internal; + + if (sm->cdir == sm->root) + { + f=mpio_fatentry_new(m, mem, 0, FTYPE_MUSIC); + mpio_io_block_delete(m, mem, f); + free(f); + + memset(dummy, 0x00, BLOCK_SIZE); + + /* only write the root dir */ + for (i= 0; i< 0x20; i++) + { + + if (iroot->dir + SECTOR_SIZE * i)); + } else { + /* fill the rest of the block with zeros */ + mpio_io_sector_write(m, mem, i, dummy); + } + } + } else { + mpio_directory_write(m, mem, sm->cdir); + } + + } + + if (mem == MPIO_EXTERNAL_MEM) + { + sm=&m->external; + + memset(dummy, 0xff, BLOCK_SIZE); + + for (i = 0; i < (sm->dir_offset + DIR_NUM) ; i++) { + /* before writing to a new block delete it! */ + if (((i / 0x20) * 0x20) == i) { + block = mpio_zone_block_find_seq(m, mem, (i/0x20)); + if (block == MPIO_BLOCK_NOT_FOUND) + { + block = mpio_zone_block_find_free_seq(m, mem, (i/0x20)); + } + if (block == MPIO_BLOCK_NOT_FOUND) + { + debug("This should never happen!"); + exit(-1); + } + + mpio_io_block_delete_phys(m, mem, block); + } + + /* remeber: logical sector 0 is the MBR! */ + if (i == 0) + mpio_io_sector_write(m, mem, 0, sm->mbr); + if ((i > 0) && (i < sm->pbr_offset)) + mpio_io_sector_write(m, mem, i, dummy); + + if (i == sm->pbr_offset) + mpio_io_sector_write(m, mem, sm->pbr_offset, sm->pbr); + + if ((i >= sm->fat_offset) && (i < (sm->fat_offset + (2*sm->fat_size)))) + mpio_io_sector_write(m, mem, i, + (sm->fat + SECTOR_SIZE * + ((i - sm->fat_offset) % sm->fat_size))); + + if (i>=sm->dir_offset) + mpio_io_sector_write(m, mem, i, + (sm->root->dir + + (i - sm->dir_offset) * SECTOR_SIZE)); + } + + if (sm->cdir != sm->root) + mpio_directory_write(m, mem, sm->cdir); + + } + + + return 0; +} + +int +mpio_fatentry_set_free (mpio_t *m, mpio_mem_t mem, mpio_fatentry_t *f) +{ + int e; + mpio_smartmedia_t *sm; + + if (mem == MPIO_INTERNAL_MEM) + { + sm = &m->internal; + e = f->entry * 0x10; + memset((sm->fat+e), 0xff, 0x10); + } + + if (mem == MPIO_EXTERNAL_MEM) + { + sm = &m->internal; + mpio_fatentry_write(m, mem, f, 0); + } + + return 0; +} + +int +mpio_fatentry_set_defect(mpio_t *m, mpio_mem_t mem, mpio_fatentry_t *f) +{ + int e; + mpio_smartmedia_t *sm; + + if (mem == MPIO_INTERNAL_MEM) + { + sm = &m->internal; + e = f->entry * 0x10; + memset((sm->fat+e), 0xaa, 0x10); + } + + if (mem == MPIO_EXTERNAL_MEM) + { + sm = &m->internal; + mpio_fatentry_write(m, mem, f, 0xfff7); + } + + return 0; +} + +int +mpio_fatentry_is_defect(mpio_t *m, mpio_mem_t mem, mpio_fatentry_t *f) +{ + int e; + mpio_smartmedia_t *sm; + + if (mem == MPIO_INTERNAL_MEM) + { + sm = &m->internal; + e = f->entry * 0x10; + if (mpio_fatentry_free(m, mem, f)) + return 0; + /* check if this block became defective */ + if (m->model >= MPIO_MODEL_FD100) { + /* newer models */ + if ((sm->fat[e+0x0f] != 0) || + (sm->fat[e+0x01] != sm->fat[e+0x0e])) + { + debug("defective block encountered, abort reading! (newer models check)\n"); + return 1; + } + } else + if ((sm->fat[e+0x0e] != 'P') || + (sm->fat[e+0x0f] != 'C') || + ((sm->fat[e+0x00] != 0xaa) && + (sm->fat[e+0x00] != 0xee))) + { + debug("defective block encountered, abort reading! (older models check)\n"); + return 1; + } + } + + if (mem == MPIO_EXTERNAL_MEM) + { + if (mpio_fatentry_read(m, mem, f)==0xfff7) + return 1; + } + + return 0; +} + +int +mpio_fatentry_set_eof(mpio_t *m, mpio_mem_t mem, mpio_fatentry_t *f) +{ + int e; + mpio_smartmedia_t *sm; + + if (mem == MPIO_INTERNAL_MEM) + { + sm = &m->internal; + e = f->entry * 0x10; + memset((f->i_fat+0x07), 0xff, 4); + memcpy((sm->fat+e), f->i_fat, 0x10); + } + + if (mem == MPIO_EXTERNAL_MEM) + { + sm = &m->internal; + mpio_fatentry_write(m, mem, f, 0xffff); + } + + return 0; +} + +int +mpio_fatentry_set_next(mpio_t *m, mpio_mem_t mem, + mpio_fatentry_t *f, mpio_fatentry_t *value) +{ + int e; + mpio_smartmedia_t *sm; + + if (mem == MPIO_INTERNAL_MEM) + { + sm = &m->internal; + e = f->entry * 0x10; + + f->i_fat[0x07]= value->hw_address / 0x1000000; + f->i_fat[0x08]=(value->hw_address / 0x10000 ) & 0xff; + f->i_fat[0x09]=(value->hw_address / 0x100 ) & 0xff; + f->i_fat[0x0a]= value->hw_address & 0xff; + + memcpy((sm->fat+e), f->i_fat, 0x10); + } + + if (mem == MPIO_EXTERNAL_MEM) + { + sm = &m->internal; + mpio_fatentry_write(m, mem, f, value->entry); + } + + return 0; +} + diff --git a/libmpio/src/fat.h b/libmpio/src/fat.h new file mode 100644 index 0000000..adb359b --- /dev/null +++ b/libmpio/src/fat.h @@ -0,0 +1,87 @@ +/* + * + * $Id: fat.h,v 1.1 2003/04/23 08:34:15 crunchy Exp $ + * + * Library for USB MPIO-* + * + * Markus Germeier (mager@tzi.de) + * + * + * 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. + * + * */ + +#ifndef _MPIO_FAT_H_ +#define _MPIO_FAT_H_ + +#include "defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* generate fresh boot sectors for formatting of external mem */ +BYTE *mpio_mbr_gen(BYTE); +BYTE *mpio_pbr_gen(BYTE); + +/* only needed for external memory */ +int mpio_bootblocks_read(mpio_t *, mpio_mem_t); +int mpio_mbr_eval(mpio_smartmedia_t *); +int mpio_pbr_eval(mpio_smartmedia_t *); + +/* functions on the FAT for internal *and* external */ +int mpio_fat_read(mpio_t *, mpio_mem_t, mpio_callback_init_t); +int mpio_fat_write(mpio_t *, mpio_mem_t); +int mpio_fat_clear(mpio_t *, mpio_mem_t); +int mpio_fat_free_clusters(mpio_t *, mpio_mem_t); +int mpio_fat_free(mpio_t *, mpio_mem_t); + +/* functions to iterate through the FAT linked list(s) */ +mpio_fatentry_t *mpio_fatentry_new(mpio_t *, mpio_mem_t, DWORD, BYTE); +int mpio_fatentry_plus_plus(mpio_fatentry_t *); + +mpio_fatentry_t *mpio_fatentry_find_free(mpio_t *, mpio_mem_t, BYTE); +int mpio_fatentry_next_free(mpio_t *, mpio_mem_t, + mpio_fatentry_t *); +int mpio_fatentry_next_entry(mpio_t *, mpio_mem_t, + mpio_fatentry_t *); +DWORD mpio_fatentry_read(mpio_t *, mpio_mem_t, mpio_fatentry_t *); +int mpio_fatentry_write(mpio_t *, mpio_mem_t, mpio_fatentry_t *, + WORD); + +int mpio_fatentry_set_free (mpio_t *, mpio_mem_t, + mpio_fatentry_t *); +int mpio_fatentry_set_defect(mpio_t *, mpio_mem_t, + mpio_fatentry_t *); +int mpio_fatentry_set_eof(mpio_t *, mpio_mem_t, + mpio_fatentry_t *); +int mpio_fatentry_set_next(mpio_t *, mpio_mem_t, + mpio_fatentry_t *, mpio_fatentry_t *); +int mpio_fatentry_is_defect(mpio_t *, mpio_mem_t, + mpio_fatentry_t *); + +/* finding a file is fundamental different for internal mem */ +int mpio_fat_internal_find_startsector(mpio_t *, BYTE); +BYTE mpio_fat_internal_find_fileindex(mpio_t *); + +/* mapping logical <-> physical for internal memory only */ +void mpio_fatentry_hw2entry(mpio_t *, mpio_fatentry_t *); +void mpio_fatentry_entry2hw(mpio_t *, mpio_fatentry_t *); + +#ifdef __cplusplus +} +#endif + +#endif /* _MPIO_FAT_H_ */ diff --git a/libmpio/src/id3.c b/libmpio/src/id3.c new file mode 100644 index 0000000..e5aba36 --- /dev/null +++ b/libmpio/src/id3.c @@ -0,0 +1,292 @@ +/* + * $Id: id3.c,v 1.1 2003/04/23 08:34:15 crunchy Exp $ + * + * Library for accessing Digit@lways MPIO players + * Copyright (C) 2003 Markus Germeier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc.,g 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include + +#include "id3.h" +#include "debug.h" +#include "mplib.h" + +#ifdef MPLIB +void +mpio_id3_get_content(id3_tag *tag, id3_tag *tag2, int field, + BYTE out[INFO_LINE]) +{ + id3_content *content; + id3_text_content *text_content; + + content = mp_get_content(tag, field); + if (!content) + content = mp_get_content(tag2, field); + if (content) + { + text_content = mp_parse_artist(content); + debugn(2, "Found (%d): %s\n", field, text_content->text); + strncpy(out, text_content->text, INFO_LINE); + } else { + strcpy(out,""); + } + +} + +void +mpio_id3_copy_tag(BYTE *src, BYTE *dest, int *offset) +{ + int i=0; + int last=0; + + /* find last non-space character, so we can strip */ + /* trailing spaces */ + while(src[i]) + if (src[i++]!=0x20) + last=i; + + i=0; + while((*offset<(INFO_LINE-1)) && (src[i]) && (iid3 = value; + return m->id3; +#else + return 0; +#endif /* MPLIB */ +} + +/* query ID3 rewriting support */ +BYTE +mpio_id3_get(mpio_t *m) +{ +#ifdef MPLIB + return m->id3; +#else + return 0; +#endif /* MPLIB */ +} + +/* ID3 rewriting: do the work */ +/* context, src filename, uniq filename template */ +int +mpio_id3_do(mpio_t *m, BYTE *src, BYTE *tmp) +{ +#ifdef MPLIB + int fd, in; + BYTE buf[BLOCK_SIZE]; + int r, w; + int i, j, t; + id3_tag *tag, *tag2, *new_tag; + id3_tag_list *tag_list; + id3_tag_list new_tag_list; + id3_content *content; + id3_content new_content; + id3_text_content *text_content; + id3v2_tag *v2_tag; + BYTE data_artist[INFO_LINE]; + BYTE data_title[INFO_LINE]; + BYTE data_album[INFO_LINE]; + BYTE data_year[INFO_LINE]; + BYTE data_genre[INFO_LINE]; + BYTE data_comment[INFO_LINE]; + BYTE data_track[INFO_LINE]; + + BYTE mpio_tag[INFO_LINE]; + char *mpio_tag_unicode; + + char *uc; + iconv_t ic; + int fin, fout; + char *fback, *back; + + if (!m->id3) + return 0; + + sprintf(tmp, "/tmp/MPIO-XXXXXXXXXXXXXXX", INFO_LINE); + + fd = mkstemp(tmp); + if (fd==-1) return 0; + sprintf(m->id3_temp, tmp, INFO_LINE); + + in = open(src, O_RDONLY); + if (in==-1) return 0; + + do { + r=read(in, buf, BLOCK_SIZE); + if (r>0) + w=write(fd, buf, r); + } while (r>0); + + close (in); + + tag_list = mp_get_tag_list_from_fd(fd); + if (!tag_list) + { + debug("no tag list found!\n"); + return 0; + } + + tag = tag_list->tag; + tag2 = NULL; + if (tag_list->next) + tag2 = tag_list->next->tag; + + /* read tags from file */ + mpio_id3_get_content(tag, tag2, MP_ARTIST, data_artist); + mpio_id3_get_content(tag, tag2, MP_TITLE, data_title); + mpio_id3_get_content(tag, tag2, MP_ALBUM, data_album); + mpio_id3_get_content(tag, tag2, MP_GENRE, data_genre); + mpio_id3_get_content(tag, tag2, MP_COMMENT, data_comment); + mpio_id3_get_content(tag, tag2, MP_YEAR, data_year); + mpio_id3_get_content(tag, tag2, MP_TRACK, data_track); + + /* build new tag */ + mpio_tag[0]=0x00; + i=j=t=0; + + while ((t<(INFO_LINE-1) && m->id3_format[i]!=0)) + { + if (m->id3_format[i] == '%') + { + i++; + switch(m->id3_format[i]) + { + case 'p': + mpio_id3_copy_tag(data_artist, mpio_tag, &t); + break; + case 't': + mpio_id3_copy_tag(data_title, mpio_tag, &t); + break; + case 'a': + mpio_id3_copy_tag(data_album, mpio_tag, &t); + break; + case 'g': + mpio_id3_copy_tag(data_genre, mpio_tag, &t); + break; + case 'c': + mpio_id3_copy_tag(data_comment, mpio_tag, &t); + break; + case 'y': + mpio_id3_copy_tag(data_year, mpio_tag, &t); + break; + case 'n': + mpio_id3_copy_tag(data_track, mpio_tag, &t); + break; + default: + mpio_tag[t] = m->id3_format[i]; + } + } else { + mpio_tag[t] = m->id3_format[i]; + t++; + } + + i++; + } + mpio_tag[t]=0x00; + + debugn(2, "new_tag: %s\n", mpio_tag); + + /* convert tag to UNICODELITTLE */ + fin = strlen(mpio_tag) + 1; + fout = fin*2 + 2; + ic = iconv_open("UNICODELITTLE", "ASCII"); + fback = mpio_tag; + mpio_tag_unicode = (char *)malloc(2*INFO_LINE+3); + back = (char *)mpio_tag_unicode; + *back=0x01; + back++; + *back=0xff; + back++; + *back=0xfe; + back++; + + debugn(2,"iconv before %s %d %d\n", fback, fin, fout); + iconv(ic, (char **)&fback, &fin, (char **)&back, &fout); + debugn(2,"iconv after %s %d %d\n", fback, fin, fout); + iconv_close(ic); + hexdumpn(2, mpio_tag, strlen(mpio_tag)); + hexdumpn(2, (char *)mpio_tag_unicode, (2*strlen(mpio_tag))+3); + + /* build new ID3 v2 tag with only TXXX field */ + new_content.length=(2*strlen(mpio_tag))+3; + new_content.data = (char *)malloc(new_content.length); + new_content.compressed=0; + new_content.encrypted=0; + memcpy(new_content.data, mpio_tag_unicode, new_content.length); + + new_tag = mp_alloc_tag_with_version (2); + mp_set_custom_content(new_tag, "TXXX", &new_content); + + v2_tag = (id3v2_tag *)new_tag->tag; + v2_tag->header->unsyncronization=0; + v2_tag->header->is_experimental=0; + + new_tag_list.tag = new_tag; + new_tag_list.next = NULL; + new_tag_list.first = NULL; + + /* delete ID3 v2 tag from file */ + mp_del_tags_by_ver_from_fd(fd, 2); + close (fd); + + /* write new ID3 v2 tag to file */ + mp_write_to_file(&new_tag_list, tmp); + + free(mpio_tag_unicode); + + return 1; +#else + return 0; +#endif /* MPLIB */ +} + +int +mpio_id3_end(mpio_t *m) +{ +#ifdef MPLIB + if (m->id3_temp[0]) + unlink(m->id3_temp); + m->id3_temp[0] = 0x00; + return 1; +#else + return 0; +#endif /* MPLIB */ +} + +void +mpio_id3_format_set(mpio_t *m, BYTE *format) +{ + strncpy(m->id3_format, format, INFO_LINE); +} + +/* get format string for rewriting*/ +void +mpio_id3_format_get(mpio_t *m, BYTE *format) +{ + strncpy(format, m->id3_format, INFO_LINE); +} diff --git a/libmpio/src/id3.h b/libmpio/src/id3.h new file mode 100644 index 0000000..1bb549c --- /dev/null +++ b/libmpio/src/id3.h @@ -0,0 +1,44 @@ +/* + * $Id: id3.h,v 1.1 2003/04/23 08:34:15 crunchy Exp $ + * + * Library for accessing Digit@lways MPIO players + * Copyright (C) 2003 Markus Germeier + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _MPIO_ID3_H_ +#define _MPIO_ID3_H_ + +#include "defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* ID3 rewriting: do the work */ +/* context, src filename, uniq filename template */ +int mpio_id3_do(mpio_t *, BYTE *, BYTE *); + +/* ID3: clean up temp file */ +int mpio_id3_end(mpio_t *); + +#ifdef __cplusplus +} +#endif + + +#endif /* _MPIO_ID3_H_ */ diff --git a/libmpio/src/io.c b/libmpio/src/io.c new file mode 100644 index 0000000..eaaadd4 --- /dev/null +++ b/libmpio/src/io.c @@ -0,0 +1,1213 @@ +/* -*- linux-c -*- */ + +/* + * + * $Id: io.c,v 1.1 2003/04/23 08:34:15 crunchy Exp $ + * + * Library for USB MPIO-* + * + * Markus Germeier (mager@tzi.de) + * + * uses code from mpio_stat.c by + * Yuji Touya (salmoon@users.sourceforge.net) + * + * + * 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. + * + * */ + +/* + * + * low level I/O + * + * + */ + +#include +#include +#include +#include + +#include "io.h" +#include "debug.h" +#include "ecc.h" + +BYTE model2externalmem(mpio_model_t); +DWORD blockaddress_encode(DWORD); +DWORD blockaddress_decode(BYTE *); +void fatentry2hw(mpio_fatentry_t *, BYTE *, DWORD *); + +/* small hack to handle external addressing on different MPIO models */ +BYTE +model2externalmem(mpio_model_t model) +{ + BYTE m; + + switch(model) + { + case MPIO_MODEL_DMG: + case MPIO_MODEL_DMG_PLUS: + m = 0x80; + break; + default: + m = 0x10; + } + + return m; +} + +/* encoding and decoding of blockaddresses */ + +DWORD +blockaddress_encode(DWORD ba) +{ + WORD addr; + BYTE p = 0, c = 0; + BYTE high, low; + + high = 0x10 | ((ba / 0x80) & 0x07); + low = (ba * 2) & 0xff; + + c = high; + while (c) + { + if (c & 0x01) + p ^= 1; + c /= 2; + } + + c = low; + while (c) + { + if (c & 0x01) + p ^= 0x01; + c /= 2; + } + + addr = (high * 0x100) + low + p; + + return addr; +} + + +DWORD +blockaddress_decode(BYTE *entry) +{ + WORD ba; + WORD value; + BYTE p=0, high, low; + int i, t; + + /* check for "easy" defect block */ + t=1; + for(i=0; i<0x10; i++) + if (entry[i] != 0) + t=0; + if (t) + return MPIO_BLOCK_DEFECT; + + /* check for "easy" defect block */ + t=1; + for(i=0; i<0x10; i++) + if (entry[i] != 0xff) + t=0; + if (t) + return MPIO_BLOCK_FREE; + + /* check for "strange" errors */ + if ((entry[6] != entry[11]) || + (entry[7] != entry[12])) + { + debug("error: different block addresses found:\n"); + hexdumpn(1, entry, 0x10); + return MPIO_BLOCK_DEFECT; + } + + ba = entry[6] * 0x100 + entry[7]; + + /* special values */ + if (ba == 0xffff) + return MPIO_BLOCK_DEFECT; + if (ba == 0x0000) + return MPIO_BLOCK_CIS; + + /* check parity */ + value = ba; + while (value) + { + if (value & 0x01) + p ^= 0x01; + + value /= 2; + } + if (p) + { + debug("parity error found in block address: %2x\n", ba); + return MPIO_BLOCK_DEFECT; + } + + high = ((ba / 0x100) & 0x07); + low = ((ba & 0x0ff) / 2); + + return (high * 0x80 + low); +} + +/* foobar */ + +void +fatentry2hw(mpio_fatentry_t *f, BYTE *chip, DWORD *address) +{ + mpio_smartmedia_t *sm; + + if (f->mem == MPIO_INTERNAL_MEM) + { + sm = &f->m->internal; + /* hexdump((char *)&f->entry, 4); */ + /* hexdump((char *)&f->hw_address, 4); */ + *chip = f->hw_address / 0x1000000; + *address = f->hw_address & 0x0ffffff; + } + if (f->mem == MPIO_EXTERNAL_MEM) + { + sm = &f->m->external; + *chip = MPIO_EXTERNAL_MEM; + *address = mpio_zone_block_find_log(f->m, f->mem, f->entry); + debugn(3, "mager: %06x (logical: %04x)\n", *address, f->entry); + } + return; +} + +/* + * zone management + */ + +int +mpio_zone_init(mpio_t *m, mpio_cmd_t mem) +{ + mpio_smartmedia_t *sm; + int i; + int zone, block, e; + + if (mem != MPIO_EXTERNAL_MEM) + { + debug("called function with wrong memory selection!\n"); + return -1; + } + sm = &m->external; + + for(i=0; imax_blocks; i++) + { + zone = i / MPIO_ZONE_PBLOCKS; + block= i % MPIO_ZONE_PBLOCKS; + + e = i * 0x10; + + sm->zonetable[zone][block]=blockaddress_decode(sm->spare+e); + + hexdumpn(4, sm->spare+e, 0x10); + debugn(2, "decoded: %04x\n", sm->zonetable[zone][block]); + } + +} + +DWORD +mpio_zone_block_find_log(mpio_t *m, mpio_cmd_t mem, DWORD lblock) +{ + mpio_smartmedia_t *sm; + int v; + + if (mem != MPIO_EXTERNAL_MEM) + { + debug("called function with wrong memory selection!\n"); + return -1; + } + sm = &m->external; + + /* OK, I can't explain this right now, but it does work, + * see Software Driver v3.0, page 31 + */ + v = lblock + (sm->size/64); + + return (mpio_zone_block_find_seq(m, mem, v)); +} + +DWORD +mpio_zone_block_find_seq(mpio_t *m, mpio_cmd_t mem, DWORD lblock) +{ + mpio_smartmedia_t *sm; + int i, f, v; + int zone, block; + + if (mem != MPIO_EXTERNAL_MEM) + { + debug("called function with wrong memory selection!\n"); + return -1; + } + sm = &m->external; + + if ((lblock>=MPIO_BLOCK_CIS) && (lblock<(MPIO_BLOCK_CIS + BLOCK_SECTORS))) + { + zone = 0; + block = MPIO_BLOCK_CIS; + } else { + zone = lblock / MPIO_ZONE_LBLOCKS; + block = lblock % MPIO_ZONE_LBLOCKS; + } + + f=0; + for (i=(MPIO_ZONE_PBLOCKS-1); i >=0; i--) + { + + if (sm->zonetable[zone][i]==block) + { + f++; + v=i; + } + } + + if (f>1) + debug("found more than one block, using first one\n"); + + if (!f) + { + debugn(2, "block not found\n"); + return MPIO_BLOCK_NOT_FOUND; + } + + return ((zone * BLOCK_SECTORS * MPIO_ZONE_PBLOCKS ) + v * BLOCK_SECTORS); +} + +DWORD +mpio_zone_block_set_free(mpio_t *m, mpio_cmd_t mem, DWORD lblock) +{ + DWORD value; + int zone, block; + mpio_smartmedia_t *sm; + + if (mem != MPIO_EXTERNAL_MEM) + { + debug("called function with wrong memory selection!\n"); + return -1; + } + sm = &m->external; + + value = mpio_zone_block_find_log(m, mem, lblock); + + mpio_zone_block_set_free_phys(m, mem, value); + + return value; +} + +void +mpio_zone_block_set_free_phys(mpio_t *m, mpio_cmd_t mem, DWORD value) +{ + int zone, block; + mpio_smartmedia_t *sm; + + if (mem != MPIO_EXTERNAL_MEM) + { + debug("called function with wrong memory selection!\n"); + return; + } + sm = &m->external; + + zone = value / BLOCK_SECTORS; + block = zone % MPIO_ZONE_PBLOCKS; + zone = zone / MPIO_ZONE_PBLOCKS; + + sm->zonetable[zone][block] = MPIO_BLOCK_FREE; + + return; +} + +void +mpio_zone_block_set_defect_phys(mpio_t *m, mpio_cmd_t mem, DWORD value) +{ + int zone, block; + mpio_smartmedia_t *sm; + + if (mem != MPIO_EXTERNAL_MEM) + { + debug("called function with wrong memory selection!\n"); + return; + } + sm = &m->external; + + zone = value / BLOCK_SECTORS; + block = zone % MPIO_ZONE_PBLOCKS; + zone = zone / MPIO_ZONE_PBLOCKS; + + sm->zonetable[zone][block] = MPIO_BLOCK_DEFECT; + + return; +} + +void +mpio_zone_block_set(mpio_t *m, mpio_cmd_t mem, DWORD pblock) +{ + int zone, block, pb; + + pb = pblock / BLOCK_SECTORS; + zone = pb / MPIO_ZONE_PBLOCKS; + block = pb % MPIO_ZONE_PBLOCKS; + + m->external.zonetable[zone][block] = MPIO_BLOCK_FREE ; + +} + +DWORD +mpio_zone_block_find_free_log(mpio_t *m, mpio_cmd_t mem, DWORD lblock) +{ + mpio_smartmedia_t *sm; + int v; + + if (mem != MPIO_EXTERNAL_MEM) + { + debug("called function with wrong memory selection!\n"); + return -1; + } + sm = &m->external; + + /* OK, I can't explain this right now, but it does work, + * see Software Driver v3.0, page 31 + */ + v = lblock + (sm->size/64); + + return (mpio_zone_block_find_free_seq(m, mem, v)); +} + +DWORD +mpio_zone_block_find_free_seq(mpio_t *m, mpio_cmd_t mem, DWORD lblock) +{ + DWORD value; + int zone, block, i; + mpio_smartmedia_t *sm; + + if (mem != MPIO_EXTERNAL_MEM) + { + debug("called function with wrong memory selection!\n"); + return -1; + } + sm = &m->external; + + value = mpio_zone_block_find_seq(m, mem, lblock); + + if (value != MPIO_BLOCK_NOT_FOUND) + { + debug("logical block numbers is already assigned! (%4x)\n", lblock); + exit (-1); + } + + if ((lblock>=MPIO_BLOCK_CIS) && (lblock<(MPIO_BLOCK_CIS + BLOCK_SECTORS))) + { + zone = 0; + block = MPIO_BLOCK_CIS; + } else { + zone = lblock / MPIO_ZONE_LBLOCKS; + block = lblock % MPIO_ZONE_LBLOCKS; + } + + i=0; + while ((sm->zonetable[zone][i]!=MPIO_BLOCK_FREE) && (izonetable[zone][i] = block; + + return ((zone * BLOCK_SECTORS * MPIO_ZONE_PBLOCKS ) + i * BLOCK_SECTORS); +} + + +WORD +mpio_zone_block_get_logical(mpio_t *m, mpio_cmd_t mem, DWORD pblock) +{ + int zone, block, pb; + + pb = pblock / BLOCK_SECTORS; + zone = pb / MPIO_ZONE_PBLOCKS; + block = pb % MPIO_ZONE_PBLOCKS; + + return m->external.zonetable[zone][block]; +} + + + + + +/* + * low-low level functions + */ + +/* + * Set command packet + * + * parameter: + * + * cmd: commando code + * mem: internal/external + * index: sector/block + * size: size of used memory chip + * wsize: write size, only for PUT_BLOCK + * buffer: output buffer of command packet + * + */ + +int +mpio_io_set_cmdpacket(mpio_t *m, mpio_cmd_t cmd, mpio_mem_t mem, DWORD index, + WORD size, BYTE wsize, BYTE *buffer) +{ + BYTE memory; + + /* clear cmdpacket*/ + memset(buffer, 0, 0x40); + + *buffer = cmd; + memory = mem; + if (mem == MPIO_EXTERNAL_MEM) + memory = model2externalmem(m->model); + + *(buffer + 0x01) = memory; + *(buffer + 0x03) = (BYTE) (index & 0x00ff); + *(buffer + 0x04) = (BYTE)((index & 0xff00) >> 8); + /* SM cards with less or equal 32 MB only need 2 Bytes + * to address sectors or blocks. + * The highest byte has to be 0xff in that case! + */ + if (size <= 32) + { + *(buffer + 0x05) = 0xff; + } else { + *(buffer + 0x05) = (BYTE) (index >> 16); + } + /* is this always 0x48 in case of a block write ?? */ + *(buffer + 0x06) = wsize; + + memcpy((buffer + 0x3b), "jykim", 5); + + return (0); +} + +/* + * write chunk of data to MPIO filedescriptor + * + * parameter: + * + * fd: filedescriptor + * block: data buffer (has to be num_bytes) + * num_bytes: size of data buffer + * + */ +int +mpio_io_bulk_write(int fd, BYTE *block, int num_bytes) +{ + BYTE *p; + int count, bytes_left, bytes_written; + + bytes_left = num_bytes; + bytes_written = 0; + p = block; + + do + { + count = write (fd, p, bytes_left); + if (count > 0) + { + p += count; + bytes_written += count; + bytes_left -= count; + } + } while (bytes_left > 0 && count > 0); + + return bytes_written; +} + +/* + * read chunk of data from MPIO filedescriptor + * + * parameter: + * + * fd: filedescriptor + * block: return buffer (has to be num_bytes) + * num_bytes: size of return buffer + * + */ +int +mpio_io_bulk_read (int fd, BYTE *block, int num_bytes) +{ + int total_read, count, bytes_left; + BYTE *p; + + total_read = 0; + bytes_left = num_bytes; + p = block; + + do + { + count = read (fd, p, bytes_left); + + if (count > 0) + { + total_read += count; + bytes_left -= count; + p += count; + } + } while (total_read < num_bytes && count > 0); + + return total_read; +} + +/* + * low level functions + */ + +/* + * read version block from MPIO + * + * parameter: + * + * m: mpio context + * buffer: return buffer (has to be CMD_SIZE) + * + */ +int +mpio_io_version_read(mpio_t *m, BYTE *buffer) +{ + int nwrite, nread; + BYTE cmdpacket[CMD_SIZE], status[CMD_SIZE]; + + /* Send command packet to MPIO */ + mpio_io_set_cmdpacket (m, GET_VERSION, 0, 0, 0xff, 0, cmdpacket); + + debugn (5, ">>> MPIO\n"); + hexdump (cmdpacket, sizeof(cmdpacket)); + + nwrite = mpio_io_bulk_write (m->fd, cmdpacket, 0x40); + + if (nwrite != CMD_SIZE) + { + debug ("Failed to send command.\n\n"); + close (m->fd); + return 0; + } + + /* Receive packet from MPIO */ + nread = mpio_io_bulk_read (m->fd, status, 0x40); + + if (nread == -1 || nread != 0x40) + { + debug ("Failed to read Sector.\n%x\n",nread); + close (m->fd); + return 0; + } + + debugn (5, "<<< MPIO\n"); + hexdump (status, 0x40); + + memcpy(buffer, status, 0x40); + + return CMD_SIZE; +} + +/* + * read sector from SmartMedia + * + * parameter: + * + * m: mpio context + * mem: MPIO_{INTERNAL,EXTERNAL}_MEM + * index: index number of sector to read + * output: return buffer (has to be SECTOR_SIZE) + * + */ + +/* right now we assume we only want to read single sectors from + * the _first_ internal memory chip + */ + +int +mpio_io_sector_read(mpio_t *m, BYTE mem, DWORD index, BYTE *output) +{ + mpio_smartmedia_t *sm=0; + DWORD sector; + int nwrite, nread; + BYTE cmdpacket[CMD_SIZE], recvbuff[SECTOR_TRANS]; + + if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; + if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; + if (!sm) + { + debug("error in memory selection, aborting\n"); + exit (-1); + } + + if (mem == MPIO_INTERNAL_MEM) + { + sector = index; + } else { + /* find the correct physical block first! */ + if ((index>=MPIO_BLOCK_CIS) && (index<(MPIO_BLOCK_CIS + BLOCK_SECTORS))) + { + sector = mpio_zone_block_find_seq(m, mem, MPIO_BLOCK_CIS); + sector+= (index % MPIO_BLOCK_CIS); + } else { + sector = mpio_zone_block_find_seq(m, mem, (index / 0x20)); + sector+= (index % 0x20); + } + } + + debugn (2, "sector: %8x (%06x)\n", index, sector); + + mpio_io_set_cmdpacket (m, GET_SECTOR, mem, sector, sm->size, 0, cmdpacket); + + debugn (5, "\n>>> MPIO\n"); + hexdump (cmdpacket, sizeof(cmdpacket)); + + nwrite = mpio_io_bulk_write (m->fd, cmdpacket, 0x40); + + if(nwrite != CMD_SIZE) + { + debug ("\nFailed to send command.\n\n"); + close (m->fd); + return 1; + } + + /* Receive packet from MPIO */ + nread = mpio_io_bulk_read (m->fd, recvbuff, SECTOR_TRANS); + + if(nread != SECTOR_TRANS) + { + debug ("\nFailed to read Sector.\n%x\n", nread); + close (m->fd); + return 1; + } + + /* check ECC Area information */ + if (mem==MPIO_EXTERNAL_MEM) + { + if (mpio_ecc_256_check (recvbuff, + (recvbuff + SECTOR_SIZE + 13)) || + mpio_ecc_256_check ((recvbuff + (SECTOR_SIZE / 2)), + (recvbuff + SECTOR_SIZE + 8)) ) + debug ("ECC error @ (%02x : %06x)\n", mem, index); + } + + /* This should not be needed: + * we don't have ECC information for the internal memory + * we only read the directory through this function + */ + /* if (mem==MPIO_INTERNAL_MEM) */ + /* { */ + /* debugn(2, "WARNING, code for internal FAT entry (in ECC area)" */ + /* " not yet in place!!\n"); */ + /* } */ + + debugn (5, "\n<<< MPIO\n"); + hexdump (recvbuff, SECTOR_TRANS); + + memcpy(output, recvbuff, SECTOR_SIZE); + + return 0; +} + +/* + * write sector to SmartMedia + * + * parameter: + * + * m: mpio context + * mem: MPIO_{INTERNAL,EXTERNAL}_MEM + * index: index number of sector to read + * input: data buffer (has to be SECTOR_SIZE) + * + */ + +/* right now we assume we only want to write single sectors from + * the _first_ internal memory chip + */ + +int +mpio_io_sector_write(mpio_t *m, BYTE mem, DWORD index, BYTE *input) +{ + int nwrite; + mpio_smartmedia_t *sm; + DWORD pvalue; + DWORD block_address, ba; + BYTE cmdpacket[CMD_SIZE], sendbuff[SECTOR_TRANS]; + + if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; + if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; + if (!sm) + { + debug("error in memory selection, aborting\n"); + exit (-1); + } + + /* we have to: + * - find the physical block (or allocate a new one) + * - calculate the logical block for zone management + */ + + if (mem == MPIO_EXTERNAL_MEM) + { + if (index==MPIO_BLOCK_DEFECT) + { + block_address = 0; + pvalue = 0; + } else { + if ((index>=MPIO_BLOCK_CIS) && + (index<(MPIO_BLOCK_CIS + BLOCK_SECTORS))) + { + block_address = 0; + if (index==MPIO_BLOCK_CIS) + { + pvalue=mpio_zone_block_find_free_seq(m, mem, index); + } else { + /* find the block from the block list! */ + pvalue=mpio_zone_block_find_seq(m, mem, MPIO_BLOCK_CIS); + } + if (pvalue != MPIO_BLOCK_NOT_FOUND) + pvalue = pvalue + index - MPIO_BLOCK_CIS; + + } else { + block_address = blockaddress_encode(index / BLOCK_SECTORS); + if ((index % BLOCK_SECTORS) == 0) + { + /* this is the first write to the block: allocate a new one */ + /* ... and mark it with the block_address */ + pvalue=mpio_zone_block_find_free_seq(m, mem, + (index / BLOCK_SECTORS)); + } else { + /* find the block from the block list! */ + pvalue=mpio_zone_block_find_seq(m, mem, (index / BLOCK_SECTORS)); + } + if (pvalue != MPIO_BLOCK_NOT_FOUND) + pvalue = pvalue + (index % BLOCK_SECTORS); + + } + + if (pvalue == MPIO_BLOCK_NOT_FOUND) + { + debug ("Oops, this should never happen! (%6x : %6x)\n", + index, block_address); + exit (-1); + } + } + } else { + pvalue = index; + } + + mpio_io_set_cmdpacket(m, PUT_SECTOR, mem, pvalue, sm->size, 0, cmdpacket); + + debugn (5, "\n>>> MPIO\n"); + hexdump (cmdpacket, sizeof(cmdpacket)); + + nwrite = mpio_io_bulk_write(m->fd, cmdpacket, 0x40); + + if(nwrite != CMD_SIZE) + { + debug ("\nFailed to send command.\n\n"); + close (m->fd); + return 1; + } + + memset(sendbuff, 0, SECTOR_TRANS); + memset(sendbuff + SECTOR_SIZE, 0xff, 0x10); + memcpy(sendbuff, input, SECTOR_SIZE); + + if (mem==MPIO_EXTERNAL_MEM) + { + if (index == MPIO_BLOCK_DEFECT) { + memset(sendbuff + SECTOR_SIZE, 0, 0x10); + mpio_zone_block_set_defect_phys(m, mem, pvalue); + } else { + + /* generate ECC information for spare area ! */ + mpio_ecc_256_gen(sendbuff, + sendbuff + SECTOR_SIZE + 0x0d); + mpio_ecc_256_gen(sendbuff + (SECTOR_SIZE / 2), + sendbuff + SECTOR_SIZE + 0x08); + if (index == MPIO_BLOCK_DEFECT) { + memset(sendbuff + SECTOR_SIZE, 0, 0x10); + } else { + if (index == MPIO_BLOCK_CIS) { + memset(sendbuff + SECTOR_SIZE + 0x06, 0, 2); + memset(sendbuff + SECTOR_SIZE + 0x0b, 0, 2); + } else { + ba = (block_address / 0x100) & 0xff; + sendbuff[SECTOR_SIZE + 0x06] = ba; + sendbuff[SECTOR_SIZE + 0x0b] = ba; + + ba = block_address & 0xff; + sendbuff[SECTOR_SIZE + 0x07] = ba; + sendbuff[SECTOR_SIZE + 0x0c] = ba; + } + } + + } + } + + /* easy but working, we write back the FAT info we read before */ + if (mem==MPIO_INTERNAL_MEM) + memcpy((sendbuff+SECTOR_SIZE), sm->fat, 0x10); + + debugn (5, "\n>>> MPIO\n"); + hexdump(sendbuff, SECTOR_TRANS); + + /* write sector MPIO */ + nwrite = mpio_io_bulk_write(m->fd, sendbuff, SECTOR_TRANS); + + if(nwrite != SECTOR_TRANS) + { + debug ("\nFailed to read Sector.\n%x\n", nwrite); + close (m->fd); + return 1; + } + + return 0; +} + +/* + * read/write of blocks + */ +int +mpio_io_block_read(mpio_t *m, mpio_mem_t mem, mpio_fatentry_t *f, BYTE *output) +{ + int i=0; + int nwrite, nread; + mpio_smartmedia_t *sm; + BYTE chip; + DWORD address; + BYTE cmdpacket[CMD_SIZE], recvbuff[BLOCK_TRANS]; + + if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; + if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; + + fatentry2hw(f, &chip, &address); + + mpio_io_set_cmdpacket(m, GET_BLOCK, chip, address, sm->size, 0, cmdpacket); + + debugn(5, "\n>>> MPIO\n"); + hexdump(cmdpacket, sizeof(cmdpacket)); + + nwrite = mpio_io_bulk_write(m->fd, cmdpacket, CMD_SIZE); + + if(nwrite != CMD_SIZE) + { + debug ("\nFailed to send command.\n\n"); + close (m->fd); + return 1; + } + + /* Receive packet from MPIO */ + nread = mpio_io_bulk_read(m->fd, recvbuff, BLOCK_TRANS); + + if(nread != BLOCK_TRANS) + { + debug ("\nFailed to read Block.\n%x\n",nread); + close (m->fd); + return 1; + } + + debugn(5, "\n<<< MPIO\n"); + hexdump(recvbuff, BLOCK_TRANS); + + for (i = 0; i < BLOCK_SECTORS; i++) + { + /* check ECC Area information */ + if (mem==MPIO_EXTERNAL_MEM) { + if (mpio_ecc_256_check ((recvbuff + (i * SECTOR_TRANS)), + ((recvbuff +(i * SECTOR_TRANS) + + SECTOR_SIZE +13))) || + mpio_ecc_256_check ((recvbuff + (i * SECTOR_TRANS) + + (SECTOR_SIZE / 2)), + ((recvbuff +(i * SECTOR_TRANS) + + SECTOR_SIZE + 8)))) + debug ("ECC error @ (%02x : %06x)\n", chip, address); + } + + memcpy(output + (i * SECTOR_SIZE), + recvbuff + (i * SECTOR_TRANS), + SECTOR_SIZE); + } + + return 0; +} + +/* Read spare is only usefull for the internal memory, + * the FAT lies there. It is updated during the + * mpio_io_{sector,block}_{read,write} operations. + * + * For external SmartMedia cards we have a "seperate" FAT + * which is read and updated just like on a regular floppy + * disc or hard drive. + * + */ + +int +mpio_io_spare_read(mpio_t *m, BYTE mem, DWORD index, WORD size, + BYTE wsize, BYTE *output, int toread, + mpio_callback_init_t progress_callback) +{ + mpio_smartmedia_t *sm; + int i; + int nwrite, nread; + int chip = 0; + int chips = 0; + BYTE cmdpacket[CMD_SIZE]; + + if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; + if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; + + chips = sm->chips; + + for (chip = 1; chip <= chips; chip++) + { + if (mem == MPIO_INTERNAL_MEM) + mpio_io_set_cmdpacket(m, GET_SPARE_AREA, (1 << (chip-1)), + index, (size / sm->chips), + wsize, cmdpacket); + if (mem == MPIO_EXTERNAL_MEM) + mpio_io_set_cmdpacket(m, GET_SPARE_AREA, mem, index, size, + wsize, cmdpacket); + debugn(5, "\n>>> MPIO\n"); + hexdump(cmdpacket, sizeof(cmdpacket)); + + nwrite = mpio_io_bulk_write(m->fd, cmdpacket, CMD_SIZE); + + if(nwrite != CMD_SIZE) { + debug ("\nFailed to send command.\n\n"); + close (m->fd); + return 1; + } + + /* Receive packet from MPIO */ + for (i = 0; i < (toread / chips / CMD_SIZE); i++) + { + nread = mpio_io_bulk_read (m->fd, + output + (i * CMD_SIZE) + + (toread / chips * (chip - 1)), + CMD_SIZE); + + if ((progress_callback) && (i % 256)) + (*progress_callback)(mem, + (i*CMD_SIZE+(toread/chips*(chip-1))), + toread ); + + if(nread != CMD_SIZE) + { + debug ("\nFailed to read Block.\n%x\n",nread); + close (m->fd); + return 1; + } + debugn(5, "\n<<< MPIO\n"); + hexdump(output + (i * CMD_SIZE) + (toread / chips * (chip - 1)), + CMD_SIZE); + } + } + if (progress_callback) + (*progress_callback)(mem, toread, toread); + + return 0; +} + +int +mpio_io_block_delete(mpio_t *m, mpio_mem_t mem, mpio_fatentry_t *f) +{ + BYTE chip=0; + DWORD address; + mpio_smartmedia_t *sm; + + if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; + if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; + + fatentry2hw(f, &chip, &address); + + if (address == MPIO_BLOCK_NOT_FOUND) + { + debug("hmm, what happens here? (%4x)\n", f->entry); + return 0; + } + + return (mpio_io_block_delete_phys(m, chip, address)); +} + +int +mpio_io_block_delete_phys(mpio_t *m, BYTE chip, DWORD address) +{ + mpio_smartmedia_t *sm; + int nwrite, nread; + BYTE cmdpacket[CMD_SIZE], status[CMD_SIZE]; + + /* Send command packet to MPIO */ + + if (chip == MPIO_INTERNAL_MEM) sm = &m->internal; + /* hack to support 2+4 internal chips + * who ever allowed me to write code??? -mager + */ + if (chip == (MPIO_INTERNAL_MEM+1)) sm = &m->internal; + if (chip == (MPIO_INTERNAL_MEM+3)) sm = &m->internal; + if (chip == (MPIO_INTERNAL_MEM+7)) sm = &m->internal; + if (chip == MPIO_EXTERNAL_MEM) + { + sm = &m->external; + mpio_zone_block_set_free_phys(m, chip, address); + } + + mpio_io_set_cmdpacket(m, DEL_BLOCK, chip, address, sm->size, 0, cmdpacket); + + debugn (5, ">>> MPIO\n"); + hexdump (cmdpacket, sizeof(cmdpacket)); + + nwrite = mpio_io_bulk_write(m->fd, cmdpacket, 0x40); + + if (nwrite != CMD_SIZE) + { + debug ("Failed to send command.\n\n"); + close (m->fd); + return 0; + } + +/* Receive packet from MPIO */ + nread = mpio_io_bulk_read (m->fd, status, CMD_SIZE); + + if ((nread == -1) || (nread != CMD_SIZE)) + { + debug ("Failed to read Sector.\n%x\n",nread); + close (m->fd); + return 0; + } + + debugn(5, "<<< MPIO\n"); + hexdump(status, CMD_SIZE); + + if (status[0] != 0xc0) + { + debugn (2,"error formatting Block %02x:%06x\n", + chip, address); + if (chip == MPIO_EXTERNAL_MEM) + { + sm = &m->external; + mpio_zone_block_set_defect_phys(m, chip, address); + } + } + + return CMD_SIZE; +} + +int +mpio_io_block_write(mpio_t *m, mpio_mem_t mem, mpio_fatentry_t *f, BYTE *data) +{ + mpio_smartmedia_t *sm; + int nwrite; + int i; + DWORD block_address, ba; + BYTE cmdpacket[CMD_SIZE], sendbuff[BLOCK_TRANS]; + BYTE chip=0; + DWORD address; + + if (mem == MPIO_INTERNAL_MEM) + { + sm = &m->internal; + fatentry2hw(f, &chip, &address); + } + + if (mem == MPIO_EXTERNAL_MEM) + { + sm = &m->external; + /* find free physical block */ + chip = MPIO_EXTERNAL_MEM; + address = mpio_zone_block_find_free_log(m, mem, f->entry); + } + + /* build block for transfer to MPIO */ + for (i = 0; i < BLOCK_SECTORS; i++) + { + memcpy(sendbuff + (i * SECTOR_TRANS), + data + (i * SECTOR_SIZE), + SECTOR_SIZE); + memset(sendbuff + (i * SECTOR_TRANS) + SECTOR_SIZE, + 0xff, CMD_SIZE); + + if (mem == MPIO_INTERNAL_MEM) + { + if (i == 0) + { + memcpy((sendbuff+SECTOR_SIZE+(i * SECTOR_TRANS)), + f->i_fat, 0x10); +/* debug("address %02x:%06x\n", chip, address); */ +/* hexdumpn(0, f->i_fat, 0x10); */ + } + } + + /* fill in block information */ + if (mem == MPIO_EXTERNAL_MEM) + { + block_address = mpio_zone_block_get_logical(m, mem, address); + block_address = blockaddress_encode(block_address); + + ba = (block_address / 0x100) & 0xff; + sendbuff[(i * SECTOR_TRANS) + SECTOR_SIZE + 0x06] = ba; + sendbuff[(i * SECTOR_TRANS) + SECTOR_SIZE + 0x0b] = ba; + + ba = block_address & 0xff; + sendbuff[(i * SECTOR_TRANS) + SECTOR_SIZE + 0x07] = ba; + sendbuff[(i * SECTOR_TRANS) + SECTOR_SIZE + 0x0c] = ba; + + /* generate ECC Area information */ + mpio_ecc_256_gen ((sendbuff + (i * SECTOR_TRANS)), + ((sendbuff + (i * SECTOR_TRANS) + + SECTOR_SIZE + 13))); + mpio_ecc_256_gen ((sendbuff + (i * SECTOR_TRANS) + + (SECTOR_SIZE / 2)), + ((sendbuff + (i * SECTOR_TRANS) + + SECTOR_SIZE + 8))); + } + } + + mpio_io_set_cmdpacket(m, PUT_BLOCK, chip, address, sm->size, 0x48 , cmdpacket); + + debugn(5, "\n>>> MPIO\n"); + hexdump(cmdpacket, sizeof(cmdpacket)); + + nwrite = mpio_io_bulk_write(m->fd, cmdpacket, CMD_SIZE); + + if(nwrite != CMD_SIZE) + { + debug ("\nFailed to send command.\n\n"); + close (m->fd); + return 1; + } + + /* send packet to MPIO */ + debugn(5, "\n<<< MPIO\n"); + hexdump(sendbuff, BLOCK_TRANS); + nwrite = mpio_io_bulk_write (m->fd, sendbuff, BLOCK_TRANS); + + if(nwrite != BLOCK_TRANS) + { + debug ("\nFailed to read Block.\n%x\n",nwrite); + close (m->fd); + return 1; + } + + return 0; +} diff --git a/libmpio/src/io.h b/libmpio/src/io.h new file mode 100644 index 0000000..9b5df11 --- /dev/null +++ b/libmpio/src/io.h @@ -0,0 +1,95 @@ +/* -*- linux-c -*- */ + +/* + * + * $Id: io.h,v 1.1 2003/04/23 08:34:15 crunchy Exp $ + * + * Library for USB MPIO-* + * + * Markus Germeier (mager@tzi.de) + * + * uses code from mpio_stat.c by + * Yuji Touya (salmoon@users.sourceforge.net) + * + * + * 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. + * + * */ + +#ifndef _MPIO_IO_H_ +#define _MPIO_IO_H_ + +#include "defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* phys.<->log. block mapping */ +int mpio_zone_init(mpio_t *, mpio_cmd_t); +/* context, memory bank, logical block */ +/* returns address of physical block! */ +DWORD mpio_zone_block_find_log(mpio_t *, mpio_cmd_t, DWORD); + /* context, memory bank, sequential block (for sector addressing) */ +/* returns address of physical block! */ +DWORD mpio_zone_block_find_seq(mpio_t *, mpio_cmd_t, DWORD); +/* context, memory bank, logical block */ +/* find used physical block and mark it as unused! */ +/* returns address of physical block! (to delete the physical block!) */ +DWORD mpio_zone_block_set_free(mpio_t *, mpio_cmd_t, DWORD); +/* context, memory bank, physical block */ +void mpio_zone_block_set_free_phys(mpio_t *, mpio_cmd_t, DWORD); +/* context, memory bank, physical block */ +void mpio_zone_block_set_defect_phys(mpio_t *, mpio_cmd_t, DWORD); +/* context, memory bank, logical block */ +/* looks for a free physical block to be used for given logical block */ +/* mark the found block used for this logical block */ +/* returns address of physical block! */ +DWORD mpio_zone_block_find_free_log(mpio_t *, mpio_cmd_t, DWORD); +DWORD mpio_zone_block_find_free_seq(mpio_t *, mpio_cmd_t, DWORD); +/* return zone-logical block for a given physical block */ +WORD mpio_zone_block_get_logical(mpio_t *, mpio_cmd_t, DWORD); + + +/* real I/O */ +int mpio_io_set_cmdpacket(mpio_t *, mpio_cmd_t, mpio_mem_t, + DWORD, WORD, BYTE, BYTE *); + +int mpio_io_bulk_read (int, BYTE *, int); +int mpio_io_bulk_write(int, BYTE *, int); + +/* read version block into memory */ +int mpio_io_version_read(mpio_t *, BYTE *); + +/* */ +int mpio_io_sector_read (mpio_t *, BYTE, DWORD, BYTE *); +int mpio_io_sector_write(mpio_t *, BYTE, DWORD, BYTE *); + +/* */ +int mpio_io_block_read (mpio_t *, mpio_mem_t, mpio_fatentry_t *, BYTE *); +int mpio_io_block_write (mpio_t *, mpio_mem_t, mpio_fatentry_t *, BYTE *); +int mpio_io_block_delete(mpio_t *, mpio_mem_t, mpio_fatentry_t *); +/* needed for formatting of external memory */ +int mpio_io_block_delete_phys(mpio_t *, BYTE, DWORD); + +/* */ +int mpio_io_spare_read (mpio_t *, BYTE, DWORD, WORD, BYTE, BYTE *, int, + mpio_callback_init_t); + +#ifdef __cplusplus +} +#endif + +#endif /* _MPIO_IO_H_ */ diff --git a/libmpio/src/mpio.c b/libmpio/src/mpio.c new file mode 100644 index 0000000..894b6f8 --- /dev/null +++ b/libmpio/src/mpio.c @@ -0,0 +1,1301 @@ +/* + * + * $Id: mpio.c,v 1.1 2003/04/23 08:34:15 crunchy Exp $ + * + * Library for USB MPIO-* + * + * Markus Germeier (mager@tzi.de) + * + * uses code from mpio_stat.c by + * Yuji Touya (salmoon@users.sourceforge.net) + * + * + * 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 +#include +#include +#include +#include +#include + +#include "cis.h" +#include "defs.h" +#include "debug.h" +#include "directory.h" +#include "io.h" +#include "mpio.h" +#include "smartmedia.h" +#include "fat.h" + +void mpio_bail_out(void); +void mpio_init_internal(mpio_t *); +void mpio_init_external(mpio_t *); +int mpio_check_filename(mpio_filename_t); + +int mpio_file_get_real(mpio_t *, mpio_mem_t, mpio_filename_t, mpio_filename_t, + mpio_callback_t, BYTE **); + +int mpio_file_put_real(mpio_t *, mpio_mem_t, mpio_filename_t, mpio_filename_t, + mpio_filetype_t, mpio_callback_t, BYTE *, int); + +static BYTE *mpio_model_name[] = { + "MPIO-DME", + "MPIO-DMG", + "MPIO-DMG+", + "MPIO-DMB", + "MPIO-DMB+", + "MPIO-DMK", + "MPIO-FD100", + "MPIO-FL100", + "MPIO-FY100", + "unknown" +}; + +static mpio_error_t mpio_errors[] = { + { MPIO_ERR_FILE_NOT_FOUND, + "The selected file can not be found." }, + { MPIO_ERR_NOT_ENOUGH_SPACE, + "There is not enough space left on the selected memory card." }, + { MPIO_ERR_FILE_EXISTS, + "The selected file already exists and can not be overwritten. Remove it first." }, + { MPIO_ERR_FAT_ERROR, + "Internal error while reading the FAT." }, + { MPIO_ERR_READING_FILE, + "The selected file can not be read." }, + { MPIO_ERR_PERMISSION_DENIED, + "There are not enough rights to access the file/directory." }, + { MPIO_ERR_WRITING_FILE, + "There are no permisson to write to the selected file." }, + { MPIO_ERR_DIR_TOO_LONG, + "The selected directory name is to long." }, + { MPIO_ERR_DIR_NOT_FOUND, + "The selected directory can not be found." }, + { MPIO_ERR_DIR_NOT_A_DIR, + "The selected directory is not a directory." }, + { MPIO_ERR_DIR_NAME_ERROR, + "The selected directory name is not allowed." }, + { MPIO_ERR_DIR_NOT_EMPTY, + "The selected directory is not empty." }, + { MPIO_ERR_DEVICE_NOT_READY, + "Could not open " MPIO_DEVICE "\n" + "Verify that the mpio module is loaded and " + "your MPIO is\nconnected and powered up.\n" }, + { MPIO_ERR_OUT_OF_MEMORY, + "Out of Memory." }, + { MPIO_ERR_INTERNAL, + "Oops, internal ERROR. :-(" }, + { MPIO_ERR_INT_STRING_INVALID, + "Internal Error: Supported is invalid!" } +}; + +static const int mpio_error_num = sizeof mpio_errors / sizeof(mpio_error_t); + +static int _mpio_errno = 0; + +#define MPIO_ERR_RETURN(err) { mpio_id3_end(m); _mpio_errno = err; return -1 ; } + +#define MPIO_CHECK_FILENAME(filename) \ + if (!mpio_check_filename(filename)) { \ + MPIO_ERR_RETURN(MPIO_ERR_INT_STRING_INVALID); \ + } + +void +mpio_bail_out(void){ + printf("I'm utterly confused and aborting now, sorry!"); + printf("Please report this to: mpio-devel@lists.sourceforge.net\n"); + exit(1); +} + +int +mpio_check_filename(mpio_filename_t filename) +{ + BYTE *p=filename; + + while (p < (filename + MPIO_FILENAME_LEN)) + { + if (*p) + return 1; + p++; + } + + return 0; +} + +void +mpio_init_internal(mpio_t *m) +{ + mpio_smartmedia_t *sm = &m->internal; + BYTE i_offset = 0x18; + + /* init main memory parameters */ + sm->manufacturer = m->version[i_offset]; + sm->id = m->version[i_offset + 1]; + sm->chips = 1; + if (!(mpio_id_valid(m->version[i_offset]))) + { + sm->manufacturer = 0; + sm->id = 0; + sm->size = 0; + debug("WARNING: no internal memory found\n"); + return; + } + + + /* look for further installed memory chips + * models with 1, 2 and 4 chips are known + * (there _really_ shouldn't be any other versions out there ...) + */ + while ((sm->chips < 4) && + (mpio_id_valid(m->version[i_offset + (2 * sm->chips)]))) + { + if(mpio_id2mem(sm->id) != + mpio_id2mem(m->version[i_offset + (2 * sm->chips) + 1])) + { + printf("Found a MPIO with internal chips of different sizes!"); + mpio_bail_out(); + } + sm->chips++; + } + + if ((sm->chips == 3) || (sm->chips > 4)) + { + printf("Found a MPIO with %d internal chips", sm->chips); + mpio_bail_out(); + } + + sm->size = sm->chips * mpio_id2mem(sm->id); + debugn(2, "found %d chip(s) with %d MB => %d MB internal mem\n", + sm->chips, mpio_id2mem(sm->id), sm->size); + + /* used for size calculations (see mpio_memory_free) */ + mpio_id2geo(sm->id, &sm->geo); + + /* read FAT information from spare area */ + sm->max_cluster = (sm->size * 1024) / 16; /* 1 cluster == 16 KB */ + sm->max_blocks = sm->max_cluster; + debugn(2, "max_cluster: %d\n", sm->max_cluster); + /* 16 bytes per cluster */ + sm->fat_size = (sm->max_cluster * 16) / SECTOR_SIZE; + debugn(2, "fat_size: %04x\n", sm->fat_size * SECTOR_SIZE); + sm->fat = malloc(sm->fat_size * SECTOR_SIZE); + /* fat will be read in mpio_init, so we can more easily handle + a callback function */ + + if (!(sm->fat_size)) + { + printf("Some values on the way to the FAT calculations did not compute. :-(\n"); + mpio_bail_out(); + } + + + /* Read directory from internal memory */ + sm->dir_offset=0; + sm->root = malloc (sizeof(mpio_directory_t)); + sm->root->name[0] = 0; + sm->root->next = NULL; + sm->root->prev = NULL; + mpio_rootdir_read(m, MPIO_INTERNAL_MEM); + sm->cdir = sm->root; +} + +void +mpio_init_external(mpio_t *m) +{ + mpio_smartmedia_t *sm = &(m->external); + BYTE e_offset = 0x20; + + /* heuristic to find the right offset for the external memory */ + while((e_offset < 0x3a) && !(mpio_id_valid(m->version[e_offset]))) + e_offset++; + + if ((mpio_id_valid(m->version[e_offset])) && + (m->model != MPIO_MODEL_FL100)) /* ignore external memory ATM until + we know how to support it! */ + { + sm->manufacturer = m->version[e_offset]; + sm->id = m->version[e_offset + 1]; + } else { + sm->manufacturer = 0; + sm->id = 0; + sm->chips = 0; + sm->size = 0; + } + + /* init memory parameters if external memory is found */ + if (sm->id != 0) + { + /* Read things from external memory (if available) */ + sm->size = mpio_id2mem(sm->id); + sm->chips = 1; /* external is always _one_ chip !! */ + + mpio_id2geo(sm->id, &sm->geo); + + if (sm->size < 16) + { + debug("Sorry, I don't believe this software works with " + "SmartMedia Cards less than 16MB\n" + "Proceed with care and send any findings to: " + "mpio-devel@lists.sourceforge.net\n"); + } + + /* for reading the spare area later! */ + sm->max_blocks = sm->size / 16 * 1024; /* 1 cluster == 16 KB */ + sm->spare = malloc(sm->max_blocks * 0x10); + } + + /* setup directory support */ + sm->dir_offset=0; + sm->root = malloc (sizeof(mpio_directory_t)); + sm->root->name[0] = 0; + sm->root->next = NULL; + sm->root->prev = NULL; + sm->cdir = sm->root; +} + +mpio_t * +mpio_init(mpio_callback_init_t progress_callback) +{ + mpio_t *new_mpio; + mpio_smartmedia_t *sm; + int id_offset; + BYTE i; + + new_mpio = malloc(sizeof(mpio_t)); + if (!new_mpio) { + debug ("Error allocating memory for mpio_t"); + return NULL; + } + memset(new_mpio, 0, sizeof(mpio_t)); + + new_mpio->fd = open(MPIO_DEVICE, O_RDWR); + + if (new_mpio->fd < 0) { + _mpio_errno = MPIO_ERR_DEVICE_NOT_READY; + return NULL; + } + + /* Read Version Information */ + mpio_io_version_read(new_mpio, new_mpio->version); + + /* fill in values */ + snprintf(new_mpio->firmware.id, 12, "%s", new_mpio->version); + /* fix for newer versions which have a 0x00 in their version */ + for (i=0x0c ; i<0x10 ; i++) + if (new_mpio->version[i] == 0x00) + new_mpio->version[i]=' '; + snprintf(new_mpio->firmware.major, 3, "%s", new_mpio->version + 0x0c); + snprintf(new_mpio->firmware.minor, 3, "%s", new_mpio->version + 0x0e); + snprintf(new_mpio->firmware.year, 5, "%s", new_mpio->version + 0x10); + snprintf(new_mpio->firmware.month, 3, "%s", new_mpio->version + 0x14); + snprintf(new_mpio->firmware.day, 3, "%s", new_mpio->version + 0x16); + + /* there are different identification strings! */ + if (strncmp(new_mpio->version, "MPIO", 4) == 0) { + /* strings: "MPIOxy " */ + id_offset = 4; + + /* string: "MPIO-xy " */ + if (new_mpio->version[id_offset] == '-') + id_offset++; + + /* identify different versions */ + switch (new_mpio->version[id_offset]) + { + case 'E': + new_mpio->model = MPIO_MODEL_DME; + break ; + case 'K': + new_mpio->model = MPIO_MODEL_DMK; + break ; + case 'G': + new_mpio->model = MPIO_MODEL_DMG; + if (new_mpio->version[id_offset+1] == 'P') + new_mpio->model = MPIO_MODEL_DMG_PLUS; + break ; + case 'B': + new_mpio->model = MPIO_MODEL_DMB; + if (new_mpio->version[id_offset+1] == 'P') + new_mpio->model = MPIO_MODEL_DMB_PLUS; + break; + default: + new_mpio->model = MPIO_MODEL_UNKNOWN; + } + } else if (strncmp(new_mpio->version, "FD100", 5) == 0) { + new_mpio->model = MPIO_MODEL_FD100; + } else if (strncmp(new_mpio->version, "FL100", 5) == 0) { + /* we assume this model is not supported */ + new_mpio->model = MPIO_MODEL_FL100; + debug("FL100 found: External memory is ignored, because we don't know how" + " to support it at the moment (MultiMediaCards instead of SmartMedia)\n"); + } else if (strncmp(new_mpio->version, "FY100", 5) == 0) { + new_mpio->model = MPIO_MODEL_FY100; + /* I assume this is like the FD100/FL100, I didn't had the chance to + look at a FY100 firmware yet. -mager */ + debug("FY100 found: Beware, this model is not tested and we don't know" + " if it does work!\n"); + } else { + new_mpio->model = MPIO_MODEL_UNKNOWN; + } + + if (new_mpio->model == MPIO_MODEL_UNKNOWN) { + debug("Unknown version string found!\n" + "Please report this to: mpio-devel@lists.sourceforge.net\n"); + hexdumpn(1, new_mpio->version, CMD_SIZE); + } + + /* internal init */ + mpio_init_internal(new_mpio); + + /* external init */ + mpio_init_external(new_mpio); + + /* read FAT/spare area */ + if (new_mpio->internal.id) + mpio_fat_read(new_mpio, MPIO_INTERNAL_MEM, progress_callback); + + /* read the spare area (for block mapping) */ + if (new_mpio->external.id) + { + sm = &new_mpio->external; + mpio_io_spare_read(new_mpio, MPIO_EXTERNAL_MEM, 0, + sm->size, 0, sm->spare, + (sm->max_blocks * 0x10), progress_callback); + mpio_zone_init(new_mpio, MPIO_EXTERNAL_MEM); + + /* card might be defect */ + if (mpio_bootblocks_read(new_mpio, MPIO_EXTERNAL_MEM)==0) + { + sm->fat = malloc(SECTOR_SIZE*sm->fat_size); + mpio_fat_read(new_mpio, MPIO_EXTERNAL_MEM, NULL); + mpio_rootdir_read(new_mpio, MPIO_EXTERNAL_MEM); + } + } + + /* set default charset for filename conversion */ + new_mpio->charset=strdup(MPIO_CHARSET); + + /* disable ID3 rewriting support */ + new_mpio->id3=0; + strncpy(new_mpio->id3_format, MPIO_ID3_FORMAT, INFO_LINE); + new_mpio->id3_temp[0]=0x00; + + return new_mpio; +} + +/* + * returns available memory + * + * free: give back free memory size + * + */ +int +mpio_memory_free(mpio_t *m, mpio_mem_t mem, int *free) +{ + if (mem==MPIO_INTERNAL_MEM) { + if (!m->internal.size) { + *free=0; + return 0; + } + *free=mpio_fat_free_clusters(m, mem); + return (m->internal.geo.SumSector + * SECTOR_SIZE / 1000 * m->internal.chips); + } + + if (mem==MPIO_EXTERNAL_MEM) { + if (!m->external.size) { + *free=0; + return 0; + } + *free=mpio_fat_free_clusters(m, mem); + return (m->external.geo.SumSector * SECTOR_SIZE / 1000); + } + + return 0; +} + +void +mpio_close(mpio_t *m) +{ + if (m) { + close(m->fd); + + if(m->internal.fat) + free(m->internal.fat); + if(m->external.fat) + free(m->external.fat); + + free(m); + } +} + +mpio_model_t +mpio_get_model(mpio_t *m) +{ + mpio_model_t r; + + if (m) + { + r = m->model; + } else { + r = MPIO_MODEL_UNKNOWN; + } + + return r; +} + +void +mpio_get_info(mpio_t *m, mpio_info_t *info) +{ + int max=INFO_LINE-1; + snprintf(info->firmware_id, max, "\"%s\"", m->firmware.id); + snprintf(info->firmware_version, max, "%s.%s", + m->firmware.major, m->firmware.minor); + snprintf(info->firmware_date, max, "%s.%s.%s", + m->firmware.day, m->firmware.month, m->firmware.year); + snprintf(info->model, max, "%s", mpio_model_name[m->model]); + + if (!m->internal.id) + { + snprintf(info->mem_internal, max, "not available"); + } else { + if (m->internal.chips == 1) + { + snprintf(info->mem_internal, max, "%3dMB (%s)", + mpio_id2mem(m->internal.id), + mpio_id2manufacturer(m->internal.manufacturer)); + } else { + snprintf(info->mem_internal, max, "%3dMB (%s) - %d chips", + mpio_id2mem(m->internal.id)*m->internal.chips, + mpio_id2manufacturer(m->internal.manufacturer), + m->internal.chips); + } + } + + if (m->external.id) + { + snprintf(info->mem_external, max, "%3dMB (%s)", + mpio_id2mem(m->external.id), + mpio_id2manufacturer(m->external.manufacturer)); + } else { + snprintf(info->mem_external, max, "not available"); + } + +} + + +int +mpio_file_get_as(mpio_t *m, mpio_mem_t mem, mpio_filename_t filename, + mpio_filename_t as, mpio_callback_t progress_callback) +{ + return mpio_file_get_real(m, mem, filename, as, progress_callback, NULL); +} + +int +mpio_file_get(mpio_t *m, mpio_mem_t mem, mpio_filename_t filename, + mpio_callback_t progress_callback) +{ + return mpio_file_get_real(m, mem, filename, NULL, progress_callback, NULL); +} + +int +mpio_file_get_to_memory(mpio_t *m, mpio_mem_t mem, mpio_filename_t filename, + mpio_callback_t progress_callback, BYTE **memory) +{ + return mpio_file_get_real(m, mem, filename, NULL, progress_callback, memory); +} + +int +mpio_file_get_real(mpio_t *m, mpio_mem_t mem, mpio_filename_t filename, + mpio_filename_t as, mpio_callback_t progress_callback, + BYTE **memory) +{ + mpio_smartmedia_t *sm; + BYTE block[BLOCK_SIZE]; + int fd, towrite; + BYTE *p; + mpio_fatentry_t *f = 0; + struct utimbuf utbuf; + long mtime; + DWORD filesize, fsize; + BYTE abort = 0; + int merror; + + MPIO_CHECK_FILENAME(filename); + + if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; + if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; + + if(as==NULL) { + as = filename; + } + + /* find file */ + p = mpio_dentry_find_name(m, mem, filename); + if (!p) + p = mpio_dentry_find_name_8_3(m, mem, filename); + + if (p) + f = mpio_dentry_get_startcluster(m, mem, p); + + if (f && p) { + filesize=fsize=mpio_dentry_get_filesize(m, mem, p); + + if (memory) + { + *memory = malloc(filesize); + } else { + unlink(filename); + fd = open(as, (O_RDWR | O_CREAT), (S_IRWXU | S_IRGRP | S_IROTH)); + } + + do + { + mpio_io_block_read(m, mem, f, block); + + if (filesize > BLOCK_SIZE) { + towrite = BLOCK_SIZE; + } else { + towrite = filesize; + } + + if (memory) + { + memcpy((*memory)+(fsize-filesize) , block, towrite); + } else { + if (write(fd, block, towrite) != towrite) { + debug("error writing file data\n"); + close(fd); + free (f); + MPIO_ERR_RETURN(MPIO_ERR_WRITING_FILE); + } + } + + filesize -= towrite; + + if (progress_callback) + abort=(*progress_callback)((fsize-filesize), fsize); + if (abort) + debug("aborting operation"); + + } while ((((merror=(mpio_fatentry_next_entry(m, mem, f)))>0) && + (filesize>0)) && (!abort)); + + if (merror<0) + debug("defective block encountered!\n"); + + if(!memory) + { + close (fd); + free (f); + } + + /* read and copied code from mtools-3.9.8/mcopy.c + * to make this one right + */ + mtime=mpio_dentry_get_time(m, mem, p); + utbuf.actime = mtime; + utbuf.modtime = mtime; + utime(filename, &utbuf); + + } else { + debugn(2, "unable to locate the file: %s\n", filename); + _mpio_errno=MPIO_ERR_FILE_NOT_FOUND; + } + + return (fsize-filesize); +} + +int +mpio_file_put_as(mpio_t *m, mpio_mem_t mem, mpio_filename_t filename, + mpio_filename_t as, mpio_filetype_t filetype, + mpio_callback_t progress_callback) +{ + return mpio_file_put_real(m, mem, filename, as, filetype, + progress_callback, NULL,0); +} + +int +mpio_file_put(mpio_t *m, mpio_mem_t mem, mpio_filename_t filename, + mpio_filetype_t filetype, mpio_callback_t progress_callback) +{ + return mpio_file_put_real(m, mem, filename, NULL, filetype, + progress_callback, NULL,0); +} + +int +mpio_file_put_from_memory(mpio_t *m, mpio_mem_t mem, mpio_filename_t filename, + mpio_filetype_t filetype, + mpio_callback_t progress_callback, + BYTE *memory, int memory_size) +{ + return mpio_file_put_real(m, mem, filename, NULL, filetype, + progress_callback, memory, memory_size); +} + +int +mpio_file_put_real(mpio_t *m, mpio_mem_t mem, mpio_filename_t i_filename, + mpio_filename_t o_filename, mpio_filetype_t filetype, + mpio_callback_t progress_callback, + BYTE *memory, int memory_size) +{ + mpio_smartmedia_t *sm; + mpio_fatentry_t *f, current, firstblock, backup; + WORD start; + BYTE block[BLOCK_SIZE]; + BYTE use_filename[INFO_LINE]; + int fd, toread; + struct stat file_stat; + struct tm tt; + time_t curr; + int id3; + + BYTE *p = NULL; + DWORD filesize, fsize, free, blocks; + BYTE abort = 0; + + if(o_filename == NULL) { + o_filename = i_filename; + } + + MPIO_CHECK_FILENAME(o_filename); + + if (mem==MPIO_INTERNAL_MEM) sm=&m->internal; + if (mem==MPIO_EXTERNAL_MEM) sm=&m->external; + + if (memory) + { + fsize=filesize=memory_size; + } else { + id3 = mpio_id3_do(m, i_filename, use_filename); + if (!id3) + strncat(use_filename, i_filename, INFO_LINE); + if (stat((const char *)use_filename, &file_stat)!=0) { + debug("could not find file: %s\n", use_filename); + MPIO_ERR_RETURN(MPIO_ERR_FILE_NOT_FOUND); + } + fsize=filesize=file_stat.st_size; + debugn(2, "filesize: %d\n", fsize); + } + + /* check if there is enough space left */ + mpio_memory_free(m, mem, &free); + if (free*1024entry; + } + + /* find file-id for internal memory */ + if (mem==MPIO_INTERNAL_MEM) + { + f->i_index=mpio_fat_internal_find_fileindex(m); + debugn(2, "fileindex: %02x\n", f->i_index); + f->i_fat[0x01]= f->i_index; + if (m->model >= MPIO_MODEL_FD100) + f->i_fat[0x0e] = f->i_index; + start = f->i_index; + + /* number of blocks needed for file */ + blocks = filesize / 0x4000; + if (filesize % 0x4000) + blocks++; + debugn(2, "blocks: %02x\n", blocks); + f->i_fat[0x02]=(blocks / 0x100) & 0xff; + f->i_fat[0x03]= blocks & 0xff; + } + + if (!memory) + { + /* open file for reading */ + fd = open(use_filename, O_RDONLY); + if (fd==-1) + { + debug("could not open file: %s\n", use_filename); + MPIO_ERR_RETURN(MPIO_ERR_FILE_NOT_FOUND); + } + } + + while ((filesize>BLOCK_SIZE) && (!abort)) { + + if (filesize>=BLOCK_SIZE) { + toread=BLOCK_SIZE; + } else { + toread=filesize; + } + + if (memory) + { + memcpy(block, memory+(fsize-filesize), toread); + } else { + if (read(fd, block, toread)!=toread) { + debug("error reading file data\n"); + close(fd); + MPIO_ERR_RETURN(MPIO_ERR_READING_FILE); + } + } + filesize -= toread; + + /* get new free block from FAT and write current block out */ + memcpy(¤t, f, sizeof(mpio_fatentry_t)); + if (!(mpio_fatentry_next_free(m, mem, f))) + { + debug ("Found no free cluster during mpio_file_put\n" + "This should never happen\n"); + exit(-1); + } + mpio_fatentry_set_next(m ,mem, ¤t, f); + mpio_io_block_write(m, mem, ¤t, block); + + if (progress_callback) + abort=(*progress_callback)((fsize-filesize), fsize); + } + + /* handle the last block to write */ + + if (filesize>=BLOCK_SIZE) { + toread=BLOCK_SIZE; + } else { + toread=filesize; + } + + if (memory) + { + memcpy(block, memory+(fsize-filesize), toread); + } else { + if (read(fd, block, toread)!=toread) { + debug("error reading file data\n"); + close(fd); + MPIO_ERR_RETURN(MPIO_ERR_READING_FILE); + } + } + filesize -= toread; + + /* mark end of FAT chain and write last block */ + mpio_fatentry_set_eof(m ,mem, f); + mpio_io_block_write(m, mem, f, block); + + if (!memory) + close(fd); + + if (progress_callback) + (*progress_callback)((fsize-filesize), fsize); + + if (abort) + { /* delete the just written blocks, because the user + * aborted the operation + */ + debug("aborting operation\n"); + debug("removing already written blocks\n"); + + filesize=fsize; + + memcpy(¤t, &firstblock, sizeof(mpio_fatentry_t)); + memcpy(&backup, &firstblock, sizeof(mpio_fatentry_t)); + + while (mpio_fatentry_next_entry(m, mem, ¤t)) + { + mpio_io_block_delete(m, mem, &backup); + mpio_fatentry_set_free(m, mem, &backup); + memcpy(&backup, ¤t, sizeof(mpio_fatentry_t)); + + if (filesize > BLOCK_SIZE) + { + filesize -= BLOCK_SIZE; + } else { + filesize -= filesize; + } + + if (progress_callback) + (*progress_callback)((fsize-filesize), fsize); + } + mpio_io_block_delete(m, mem, &backup); + mpio_fatentry_set_free(m, mem, &backup); + + if (filesize > BLOCK_SIZE) + { + filesize -= BLOCK_SIZE; + } else { + filesize -= filesize; + } + + if (progress_callback) + (*progress_callback)((fsize-filesize), fsize); + + } else { + if (memory) + { + time(&curr); + tt = * localtime(&curr); + } + mpio_dentry_put(m, mem, + o_filename, strlen(o_filename), + ((memory)?mktime(&tt):file_stat.st_ctime), + fsize, start, 0x20); + } + + mpio_id3_end(m); + + return fsize-filesize; +} + +int +mpio_file_switch(mpio_t *m, mpio_mem_t mem, + mpio_filename_t file1, mpio_filename_t file2) +{ + BYTE *p1, *p2; + + /* find files */ + p1 = mpio_dentry_find_name(m, mem, file1); + if (!p1) + p1 = mpio_dentry_find_name_8_3(m, mem, file1); + + p2 = mpio_dentry_find_name(m, mem, file2); + if (!p2) + p2 = mpio_dentry_find_name_8_3(m, mem, file2); + + if ((!p1) || (!p2)) + MPIO_ERR_RETURN(MPIO_ERR_FILE_NOT_FOUND); + + mpio_dentry_switch(m, mem, p1, p2); + + return 0; +} + +int +mpio_file_rename(mpio_t *m, mpio_mem_t mem, + mpio_filename_t old, mpio_filename_t new) +{ + BYTE *p; + + /* find files */ + p = mpio_dentry_find_name(m, mem, old); + if (!p) + p = mpio_dentry_find_name_8_3(m, mem, old); + + if (!p) + MPIO_ERR_RETURN(MPIO_ERR_FILE_NOT_FOUND); + + mpio_dentry_rename(m, mem, p, new); + + return 0; +} + +int mpio_file_move(mpio_t *m,mpio_mem_t mem, mpio_filename_t file, + mpio_filename_t after) +{ + BYTE *p1,*p2; + + if( ( p1 = mpio_dentry_find_name(m,mem,file)) == NULL ) { + if( (p1 = mpio_dentry_find_name_8_3(m, mem, file)) == NULL ) { + MPIO_ERR_RETURN(MPIO_ERR_FILE_NOT_FOUND); + } + } + + if(after!=NULL) { + if( ( p2 = mpio_dentry_find_name(m,mem,after)) == NULL ) { + if( (p2 = mpio_dentry_find_name_8_3(m, mem, after)) == NULL ) { + MPIO_ERR_RETURN(MPIO_ERR_FILE_NOT_FOUND); + } + } + } + + fprintf(stderr," -- moving '%s' after '%s'\n",file,after); + + mpio_dentry_move(m,mem,p1,p2); + + return 0; +} + +int +mpio_memory_format(mpio_t *m, mpio_mem_t mem, + mpio_callback_t progress_callback) +{ + int data_offset; + mpio_smartmedia_t *sm; + mpio_fatentry_t *f; + DWORD clusters; + BYTE abort = 0; + BYTE *cis, *mbr, *pbr; + BYTE defect[SECTOR_SIZE]; + int i; + + if (mem == MPIO_INTERNAL_MEM) + { + sm=&m->internal; + data_offset = 0x01; + } + + if (mem == MPIO_EXTERNAL_MEM) + { + sm = &m->external; + data_offset = 0x02; + } + + clusters = sm->size*128; + + + /* TODO: read and write "Config.dat" so the player does not become "dumb" */ + if (mem==MPIO_INTERNAL_MEM) + { + /* clear the fat before anything else, so we can mark clusters defective + * if we found a bad block + */ + /* external mem must be handled diffrently, + * see comment(s) below! + */ + mpio_fat_clear(m, mem); + f = mpio_fatentry_new(m, mem, data_offset, FTYPE_MUSIC); + do + { + + if (!mpio_io_block_delete(m, mem, f)) + mpio_fatentry_set_defect(m, mem, f); + + if (progress_callback) + { + if (!abort) + { + abort=(*progress_callback)(f->entry, sm->max_cluster + 1); + if (abort) + debug("received abort signal, but ignoring it!\n"); + } else { + (*progress_callback)(f->entry, sm->max_cluster + 1); + } + } + + } while (mpio_fatentry_plus_plus(f)); + free(f); + } + + if (mem == MPIO_EXTERNAL_MEM) { + /* delete all blocks! */ + + i=0; + while (i < sm->max_blocks) + { + mpio_io_block_delete_phys(m, mem, (i * BLOCK_SECTORS)); + i++; + + if (progress_callback) + { + if (!abort) + { + abort=(*progress_callback)(i, sm->max_blocks); + if (abort) + debug("received abort signal, but ignoring it!\n"); + } else { + (*progress_callback)(i, sm->max_blocks); + } + } + + + } + + /* generate "defect" first block */ + mpio_io_sector_write(m, mem, MPIO_BLOCK_DEFECT, defect); + + /* format CIS area */ + f = mpio_fatentry_new(m, mem, MPIO_BLOCK_CIS, FTYPE_MUSIC); + /* mpio_io_block_delete(m, mem, f); */ + free(f); + cis = (BYTE *)mpio_cis_gen(); /* hmm, why this cast? */ + mpio_io_sector_write(m, mem, MPIO_BLOCK_CIS, cis); + mpio_io_sector_write(m, mem, MPIO_BLOCK_CIS+1, cis); + free(cis); + + /* generate boot blocks ... */ + mbr = (BYTE *)mpio_mbr_gen(m->external.size); + pbr = (BYTE *)mpio_pbr_gen(m->external.size); + /* ... copy the blocks to internal memory structurs ... */ + memcpy(sm->cis, cis, SECTOR_SIZE); + memcpy(sm->mbr, mbr, SECTOR_SIZE); + memcpy(sm->pbr, pbr, SECTOR_SIZE); + /* ... and set internal administration accordingly */ + mpio_mbr_eval(sm); + mpio_pbr_eval(sm); + + if (!sm->fat) /* perhaps we have to build a new FAT */ + sm->fat=malloc(sm->fat_size*SECTOR_SIZE); + mpio_fat_clear(m, mem); + + /* TODO: for external memory we have to work a little "magic" + * to identify and mark "bad blocks" (because we have a set of + * spare ones! + */ + } + + mpio_rootdir_clear(m, mem); + + /* this writes the FAT *and* the root directory */ + mpio_fat_write(m, mem); + + if (progress_callback) + (*progress_callback)(sm->max_cluster+1, sm->max_cluster+1); + + return 0; +} + +int +mpio_file_del(mpio_t *m, mpio_mem_t mem, mpio_filename_t filename, + mpio_callback_t progress_callback) +{ + BYTE *p; + mpio_smartmedia_t *sm; + mpio_fatentry_t *f, backup; + DWORD filesize, fsize; + BYTE abort=0; + + MPIO_CHECK_FILENAME(filename); + + if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; + if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; + + if ((strcmp(filename, "..") == 0) || + (strcmp(filename, ".") == 0)) + { + debugn(2, "directory name not allowed: %s\n", filename); + MPIO_ERR_RETURN(MPIO_ERR_DIR_NAME_ERROR); + } + + /* find file */ + p = mpio_dentry_find_name(m, mem, filename); + if (!p) + p = mpio_dentry_find_name_8_3(m, mem, filename); + + if (p) + f = mpio_dentry_get_startcluster(m, mem, p); + + if (f && p) { + if (mpio_dentry_is_dir(m, mem, p) == MPIO_OK) + { + /* ugly */ + mpio_directory_cd(m, mem, filename); + if (mpio_directory_is_empty(m, mem, sm->cdir) != MPIO_OK) + { + mpio_directory_cd(m, mem, ".."); + MPIO_ERR_RETURN(MPIO_ERR_DIR_NOT_EMPTY); + } else { + mpio_directory_cd(m, mem, ".."); + } + } + + filesize=fsize=mpio_dentry_get_filesize(m, mem, p); + do + { + debugn(2, "sector: %4x\n", f->entry); + + mpio_io_block_delete(m, mem, f); + + if (filesize != fsize) + mpio_fatentry_set_free(m, mem, &backup); + + memcpy(&backup, f, sizeof(mpio_fatentry_t)); + + if (filesize > BLOCK_SIZE) + { + filesize -= BLOCK_SIZE; + } else { + filesize -= filesize; + } + + if (progress_callback) + { + if (!abort) + { + abort=(*progress_callback)((fsize-filesize), fsize); + if (abort) + debug("received abort signal, but ignoring it!\n"); + } else { + (*progress_callback)((fsize-filesize), fsize); + } + } + + } while (mpio_fatentry_next_entry(m, mem, f)); +/* mpio_io_block_delete(m, mem, &backup); */ + mpio_fatentry_set_free(m, mem, &backup); + free(f); + + } else { + debugn(2, "unable to locate the file: %s\n", filename); + MPIO_ERR_RETURN(MPIO_ERR_FILE_NOT_FOUND); + } + + mpio_dentry_delete(m, mem, filename); + + return MPIO_OK; +} + +int +mpio_sync(mpio_t *m, mpio_mem_t mem) +{ + mpio_smartmedia_t *sm; + + if (mem == MPIO_INTERNAL_MEM) sm = &m->internal; + if (mem == MPIO_EXTERNAL_MEM) sm = &m->external; + + if (!sm->size) + return 0; + + /* this writes the FAT *and* the root directory */ + return mpio_fat_write(m, mem); +} + +int +mpio_health(mpio_t *m, mpio_mem_t mem, mpio_health_t *r) +{ + mpio_smartmedia_t *sm; + int i, j, zones; + mpio_fatentry_t *f; + + if (mem == MPIO_INTERNAL_MEM) + { + sm = &m->internal; + r->num = sm->chips; + + f = mpio_fatentry_new(m, mem, 0x00, FTYPE_MUSIC); + + for (i=0 ; i < sm->chips; i++) + { + r->data[i].spare = 0; + r->data[i].total = (sm->max_cluster / sm->chips); + r->data[i].broken = 0; + /* now count the broken blocks */ + for(j=0; jdata[i].total; j++) + { + if (mpio_fatentry_is_defect(m, mem, f)) + r->data[i].broken++; + mpio_fatentry_plus_plus(f); + } + } + + free(f); + + return MPIO_OK; + } + + + if (mem == MPIO_EXTERNAL_MEM) + { + sm = &m->external; + + zones = sm->max_cluster / MPIO_ZONE_LBLOCKS + 1; + r->num = zones; + + for(i=0; idata[i].spare = (i?24:22); /* first zone has only 23 due to CIS */ + r->data[i].total = MPIO_ZONE_PBLOCKS; + r->data[i].broken = 0; + /* now count the broken blocks */ + for(j=0; jzonetable[i][j] == MPIO_BLOCK_DEFECT) + r->data[i].broken++; + } + if (r->data[i].spare < r->data[i].broken) + debug("(spare blocks expect trouble!\n"); + } + return MPIO_OK; + } + + return MPIO_ERR_INTERNAL; +} + +int +mpio_memory_dump(mpio_t *m, mpio_mem_t mem) +{ + BYTE block[BLOCK_SIZE]; + int i; + + if (mem == MPIO_INTERNAL_MEM) + { + hexdump(m->internal.fat, m->internal.max_blocks*0x10); + hexdump(m->internal.root->dir, DIR_SIZE); + } + + if (mem == MPIO_EXTERNAL_MEM) + { + hexdump(m->external.spare, m->external.max_blocks*0x10); + hexdump(m->external.fat, m->external.fat_size*SECTOR_SIZE); + hexdump(m->external.root->dir, DIR_SIZE); + } + + for (i = 0 ; i<=0x100 ; i++) + mpio_io_sector_read(m, mem, i, block); + + return 0; +} + +int +mpio_errno(void) +{ + int no = _mpio_errno; + _mpio_errno = 0; + + return no; +} + +char * +mpio_strerror(int err) +{ + int i; + + if (err >= 0) return NULL; + + for (i = 0; i < mpio_error_num; i++) { + if (mpio_errors[i].id == err) + return mpio_errors[i].msg; + } + + return NULL; +} + +void +mpio_perror(char *prefix) +{ + char *msg = mpio_strerror(_mpio_errno); + + if (msg == NULL) return; + + if (prefix) + fprintf(stderr, "%s: %s\n", prefix, msg); + else + fprintf(stderr, "%s\n", msg); +} diff --git a/libmpio/src/mpio.h b/libmpio/src/mpio.h new file mode 100644 index 0000000..1d5ba3c --- /dev/null +++ b/libmpio/src/mpio.h @@ -0,0 +1,218 @@ +#/* -*- linux-c -*- */ + +/* + * $Id: mpio.h,v 1.1 2003/04/23 08:34:15 crunchy Exp $ + * + * Library for USB MPIO-* + * + * Markus Germeier (mager@tzi.de) + * + * uses code from mpio_stat.c by + * Yuji Touya (salmoon@users.sourceforge.net) + * + * + * 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. + * + * */ + +#ifndef _MPIO_H_ +#define _MPIO_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + *init and shutdown + */ + +mpio_t *mpio_init(mpio_callback_init_t); +void mpio_close(mpio_t *); + +/* + * request information + */ + +/* get version */ +void mpio_get_info(mpio_t *, mpio_info_t *); +/* get model */ +mpio_model_t mpio_get_model(mpio_t *); +/* retrieves free memory in bytes */ +int mpio_memory_free(mpio_t *, mpio_mem_t, int *free); + +/* + * charset for filename encoding/converting + */ +BYTE *mpio_charset_get(mpio_t *); +BYTE mpio_charset_set(mpio_t *, BYTE *); + +/* + * directory operations + */ + +/* context, memory bank */ +BYTE* mpio_directory_open(mpio_t *, mpio_mem_t); +/* context, memory bank, directory name */ +int mpio_directory_make(mpio_t *, mpio_mem_t, BYTE *); +/* context, memory bank, directory name */ +int mpio_directory_cd(mpio_t *, mpio_mem_t, BYTE *); +/* context, memory bank, directory name buffer space */ +void mpio_directory_pwd(mpio_t *, mpio_mem_t, BYTE pwd[INFO_LINE]); +/* context, dir context */ +BYTE* mpio_dentry_next(mpio_t *, mpio_mem_t, BYTE *); +/* context, dir context */ +int mpio_dentry_get(mpio_t *, mpio_mem_t, BYTE *, BYTE *, int,WORD *, + BYTE *, BYTE *, BYTE *, BYTE *, DWORD *, BYTE *); + +/* + * reading/writing/deleting of files + */ + +int mpio_file_get_as(mpio_t *, mpio_mem_t, mpio_filename_t, + mpio_filename_t,mpio_callback_t); + +/* context, memory bank, filename, callback */ +int mpio_file_get(mpio_t *, mpio_mem_t, mpio_filename_t, mpio_callback_t); + +/* context, memory bank, filename, filetype, callback */ +int mpio_file_put(mpio_t *, mpio_mem_t, mpio_filename_t, mpio_filetype_t, + mpio_callback_t); + +/* context, memory bank, filename, as, filetype, callback */ +int mpio_file_put_as(mpio_t *, mpio_mem_t, mpio_filename_t, + mpio_filename_t, mpio_filetype_t, + mpio_callback_t); + +/* context, memory bank, filename, callback */ +int mpio_file_del(mpio_t *, mpio_mem_t, mpio_filename_t, mpio_callback_t); + +/* + * reading/writing files into memory (used for config+font files) + */ + +/* context, memory bank, filename, callback, pointer to memory */ +/* the needed memory is allocated and the memory pointer is return */ +/* via the "BYTE **" */ + +int mpio_file_get_to_memory(mpio_t *, mpio_mem_t, mpio_filename_t, + mpio_callback_t, BYTE **); + +/* context, memory bank, filename, filetype, callback ... */ +/* ... memory pointer, size of file */ +int mpio_file_put_from_memory(mpio_t *, mpio_mem_t, mpio_filename_t, + mpio_filetype_t, mpio_callback_t, + BYTE *, int); + +/* + * rename a file on the MPIO + */ +/* context, memory bank, filename, filename */ +int mpio_file_rename(mpio_t *, mpio_mem_t, + mpio_filename_t, mpio_filename_t); + +/* + * switch position of two files + */ +/* context, memory bank, filename, filename */ +int mpio_file_switch(mpio_t *, mpio_mem_t, + mpio_filename_t, mpio_filename_t); + +/* Move a named file after a given file. If after==NULL move it + to the top of the list, +*/ + +int mpio_file_move(mpio_t *,mpio_mem_t m,mpio_filename_t,mpio_filename_t); + +/* + * formating a memory (internal mem or external SmartMedia card) + */ + +/* context, memory bank, callback */ +int mpio_memory_format(mpio_t *, mpio_mem_t, mpio_callback_t); + +/* mpio_sync has to be called after every set of mpio_file_{del,put} + * operations to write the current state of FAT and (root) directory. + * This is done explicitly to avoid writing these informations to often + * and thereby exhausting the SmartMedia chips + */ +/* context, memory bank */ +int mpio_sync(mpio_t *, mpio_mem_t); + +/* + * ID3 rewriting support + */ + +/* enable disable ID3 rewriting support */ +BYTE mpio_id3_set(mpio_t *, BYTE); +/* query ID3 rewriting support */ +BYTE mpio_id3_get(mpio_t *); + +/* set format string for rewriting*/ +void mpio_id3_format_set(mpio_t *, BYTE *); +/* get format string for rewriting*/ +void mpio_id3_format_get(mpio_t *, BYTE *); + +/* + * "special" functions + */ + +/* returns health status of selected memory */ +int mpio_health(mpio_t *, mpio_mem_t, mpio_health_t *); + +/* + * error handling + */ + +/* returns error code of last error */ +int mpio_errno(void); + +/* returns the description of the error */ +char * mpio_strerror(int err); + +/* prints the error message of the last error*/ +void mpio_perror(char *prefix); + +/* + * debugging + */ + +/* context, memory bank */ +int mpio_memory_dump(mpio_t *, mpio_mem_t); + +/* + * timeline: + * --------- + * 2004: some functions to change the order of files + * 2005: read mp3 tags of the files + */ + +#ifdef __cplusplus +} +#endif + +#endif /* _MPIO_H_ */ + + diff --git a/libmpio/src/smartmedia.c b/libmpio/src/smartmedia.c new file mode 100644 index 0000000..9b70108 --- /dev/null +++ b/libmpio/src/smartmedia.c @@ -0,0 +1,153 @@ +/* -*- linux-c -*- */ + +/* + * + * $Id: smartmedia.c,v 1.1 2003/04/23 08:34:15 crunchy Exp $ + * + * Library for USB MPIO-* + * + * Markus Germeier (mager@tzi.de) + * + * + * + * 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 +#include + +#include "smartmedia.h" +#include "debug.h" + +mpio_disk_phy_t MPIO_DISK_GEO_001={ 125, 4, 4, 2000 }; +mpio_disk_phy_t MPIO_DISK_GEO_002={ 125, 4, 8, 4000 }; +mpio_disk_phy_t MPIO_DISK_GEO_004={ 250, 4, 8, 8000 }; +mpio_disk_phy_t MPIO_DISK_GEO_008={ 250, 4, 16, 16000 }; +mpio_disk_phy_t MPIO_DISK_GEO_016={ 500, 4, 16, 32000 }; +mpio_disk_phy_t MPIO_DISK_GEO_032={ 500, 8, 16, 64000 }; +mpio_disk_phy_t MPIO_DISK_GEO_064={ 500, 8, 32, 128000 }; +mpio_disk_phy_t MPIO_DISK_GEO_128={ 500,16, 32, 256000 }; + +/* This comes from the Samsung documentation files */ + +/* a small warning: only use this function (mpio_id2mem) in the very + * beginning of MPIO model detection. After that use the values + * of size and chips! -mager + */ + +int +mpio_id2mem(BYTE id) +{ + int i=0; + + switch(id) + { + case 0xea: + i=2; + break; + case 0xe3: /* Samsung */ + case 0xe5: /* Toshiba */ + i=4; + break; + case 0xe6: + i=8; + break; + case 0x73: + i=16; + break; + case 0x75: + i=32; + break; + case 0x76: + i=64; + break; + case 0x79: + i=128; + break; + default: + debug("This should never happen (id2mem)!\n"); + exit (1); + } + return i; +} + +BYTE * +mpio_id2manufacturer(BYTE id) +{ + BYTE *m; + switch(id) + { + case 0xec: + m="Samsung"; + break; + case 0x98: + m="Toshiba"; + break; + default: + m="unknown"; + } + return m; +} + +BYTE +mpio_id_valid(BYTE id) +{ + switch(id) + { + case 0xec: /* Samsung */ + case 0x98: /* Toshiba */ + return 1; + default: + ; + } + + return 0; +} + +void +mpio_id2geo(BYTE id, mpio_disk_phy_t *geo) +{ + switch(id) + { + case 0xea: + *geo = MPIO_DISK_GEO_002; + break; + case 0xe3: /* Samsung */ + case 0xe5: /* Toshiba */ + *geo = MPIO_DISK_GEO_004; + break; + case 0xe6: + *geo = MPIO_DISK_GEO_008; + break; + case 0x73: + *geo = MPIO_DISK_GEO_016; + break; + case 0x75: + *geo = MPIO_DISK_GEO_032; + break; + case 0x76: + *geo = MPIO_DISK_GEO_064; + break; + case 0x79: + *geo = MPIO_DISK_GEO_128; + break; + default: + debug("This should never happen!\n"); + exit (1); + } + + return; +} diff --git a/libmpio/src/smartmedia.h b/libmpio/src/smartmedia.h new file mode 100644 index 0000000..57f3e3e --- /dev/null +++ b/libmpio/src/smartmedia.h @@ -0,0 +1,47 @@ +/* -*- linux-c -*- */ + +/* + * + * $Id: smartmedia.h,v 1.1 2003/04/23 08:34:15 crunchy Exp $ + * + * Library for USB MPIO-* + * + * Markus Germeier (mager@tzi.de) + * + * + * 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. + * + * */ + +#ifndef _MPIO_SMARTMEDIA_H_ +#define _MPIO_SMARTMEDIA_H_ + +#include "defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* get our configuration for SmartMedia cards right */ +int mpio_id2mem (BYTE); +BYTE * mpio_id2manufacturer(BYTE); +void mpio_id2geo(BYTE, mpio_disk_phy_t *); +BYTE mpio_id_valid(BYTE); + +#ifdef __cplusplus +} +#endif + +#endif /* _MPIO_SMARTMEDIA_H_ */ -- cgit v1.2.3