From: <ny...@us...> - 2006-12-24 05:09:19
|
Revision: 195 http://svn.sourceforge.net/pmplib/?rev=195&view=rev Author: nyaochi Date: 2006-12-23 21:09:19 -0800 (Sat, 23 Dec 2006) Log Message: ----------- [pmp_iriverplus3] - Implemented a primitive export routine for PMPlib; - "easypmp -R -L0" now works with iriver E10. Modified Paths: -------------- trunk/pmplib/include/pmp.h trunk/pmplib/lib/pmp_iriverplus3/ip3db.c trunk/pmplib/lib/pmp_iriverplus3/ip3db.h trunk/pmplib/lib/pmp_iriverplus3/pmp_iriverplus3.vcproj Added Paths: ----------- trunk/pmplib/lib/pmp_iriverplus3/pmp_iriverplus3.c Modified: trunk/pmplib/include/pmp.h =================================================================== --- trunk/pmplib/include/pmp.h 2006-12-24 02:42:41 UTC (rev 194) +++ trunk/pmplib/include/pmp.h 2006-12-24 05:09:19 UTC (rev 195) @@ -49,6 +49,7 @@ PMP_DEVICENOTFOUND, PMP_NOTSUPPORTED, PMP_INSUFFICIENTMEMORY, + PMP_NOTIMPLIMENTED, PMPDBE_OUTOFMEMORY, PMPDBE_NOTFOUND, PMPDBE_INVALIDTYPE, Modified: trunk/pmplib/lib/pmp_iriverplus3/ip3db.c =================================================================== --- trunk/pmplib/lib/pmp_iriverplus3/ip3db.c 2006-12-24 02:42:41 UTC (rev 194) +++ trunk/pmplib/lib/pmp_iriverplus3/ip3db.c 2006-12-24 05:09:19 UTC (rev 195) @@ -19,7 +19,7 @@ * */ -/* $Id:$ */ +/* $Id$ */ #ifdef HAVE_CONFIG_H #include <config.h> @@ -71,18 +71,12 @@ ip3db_init(db); } -static const ucs2char_t g_ucs2cs_datdb[] = {'d','b','.','d','a','t',0}; -static const ucs2char_t g_ucs2cs_dicdb[] = {'d','b','.','d','i','c',0}; -static const ucs2char_t g_ucs2cs_idxdb[] = {'d','b','.','i','d','x',0}; - -result_t ip3db_load(ip3db_t* db, const ucs2char_t* path) +result_t ip3db_read(ip3db_t* db, const ucs2char_t* datfn, const ucs2char_t* dicfn, const ucs2char_t* idxfn) { FILE *fp = 0; ucs2char_t filename[MAX_PATH]; - ucs2cpy(filename, path); - ucs2cat(filename, g_ucs2cs_datdb); - fp = ucs2fopen(filename, "rb"); + fp = ucs2fopen(datfn, "rb"); if (!fp) { ip3db_finish(db); return 1; @@ -90,9 +84,7 @@ fread_all(fp, &db->dat_buffer, &db->dat_size); fclose(fp); - ucs2cpy(filename, path); - ucs2cat(filename, g_ucs2cs_dicdb); - fp = ucs2fopen(filename, "rb"); + fp = ucs2fopen(dicfn, "rb"); if (!fp) { ip3db_finish(db); return 1; @@ -100,9 +92,7 @@ fread_all(fp, &db->dic_buffer, &db->dic_size); fclose(fp); - ucs2cpy(filename, path); - ucs2cat(filename, g_ucs2cs_idxdb); - fp = ucs2fopen(filename, "rb"); + fp = ucs2fopen(idxfn, "rb"); if (!fp) { ip3db_finish(db); return 1; @@ -113,7 +103,7 @@ return 0; } -result_t ip3db_dump(FILE *fpo, ip3db_t* db) +result_t ip3db_dump(ip3db_t* db, FILE *fpo) { /* Dump db.dat */ dat_t* dat = dat_new(); Modified: trunk/pmplib/lib/pmp_iriverplus3/ip3db.h =================================================================== --- trunk/pmplib/lib/pmp_iriverplus3/ip3db.h 2006-12-24 02:42:41 UTC (rev 194) +++ trunk/pmplib/lib/pmp_iriverplus3/ip3db.h 2006-12-24 05:09:19 UTC (rev 195) @@ -19,7 +19,7 @@ * */ -/* $Id:$ */ +/* $Id$ */ #ifndef __IP3DB_IP3DB_H__ #define __IP3DB_IP3DB_H__ @@ -82,7 +82,7 @@ void ip3db_init(ip3db_t* db); void ip3db_finish(ip3db_t* db); -result_t ip3db_load(ip3db_t* db, const ucs2char_t* path); -result_t ip3db_dump(FILE *fpo, ip3db_t* db); +result_t ip3db_read(ip3db_t* db, const ucs2char_t* datfn, const ucs2char_t* dicfn, const ucs2char_t* idxfn); +result_t ip3db_dump(ip3db_t* db, FILE *fpo); #endif /*_IP3DB_IP3DB_H__*/ Added: trunk/pmplib/lib/pmp_iriverplus3/pmp_iriverplus3.c =================================================================== --- trunk/pmplib/lib/pmp_iriverplus3/pmp_iriverplus3.c (rev 0) +++ trunk/pmplib/lib/pmp_iriverplus3/pmp_iriverplus3.c 2006-12-24 05:09:19 UTC (rev 195) @@ -0,0 +1,561 @@ +/* + * PMP library implementation for iriver E10. + * + * Copyright (c) 2006 Nyaochi + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +/* $Id$ */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif/*HAVE_CONFIG_H*/ +#ifdef HAVE_STRING_H +#include <string.h> +#endif/*HAVE_STRING_H*/ + +#include <os.h> +#include <stdio.h> +#include <stdlib.h> +#include <ucs2char.h> +#include <filepath.h> +#include <pmp.h> +#include <pmphelp.h> + +#include "ip3db.h" + +#ifdef PMP_IRIVERPLUS3_EXPORTS +#define PMPIRIVERPLUS3API __declspec(dllexport) +#else +#define PMPIRIVERPLUS3API +#endif + + +typedef struct { + const char *id; + const char *name; + const char *mode; + const char *min_version; + const char *max_version; + const char *sys_filename; + const char *dat_filename; + const char *dic_filename; + const char *idx_filename; + const char *path_to_music; + const char *path_to_playlist; + const char *playlist_ext; +} ip3model_descriptor_t; + +static const ip3model_descriptor_t g_model_descriptions[] = { + { + "iriver_e10_ums_1.04", "E10 UMS", "UM", + "1.04", "1.04", + "System\\E10.SYS", "System\\db.dat", "System\\db.dic", "System\\db.idx", + "\\", "Playlists\\", + ".plp", + }, + { + NULL, NULL, NULL, + NULL, NULL, + NULL, NULL, NULL, NULL, + NULL, NULL, + NULL, + }, +}; + +typedef struct { + char id[128]; + char name[128]; + char mode[128]; + char language[128]; + char version[128]; + + ucs2char_t path_to_root[MAX_PATH]; + ucs2char_t path_to_music[MAX_PATH]; + ucs2char_t path_to_playlist[MAX_PATH]; + ucs2char_t sys_filename[MAX_PATH]; + ucs2char_t dat_filename[MAX_PATH]; + ucs2char_t dic_filename[MAX_PATH]; + ucs2char_t idx_filename[MAX_PATH]; + ucs2char_t playlist_ext[MAX_PATH]; +} ip3_environment_t; + + +typedef struct { + ip3_environment_t env; +} pmp_internal_t; + +typedef struct { + ip3db_t ip3db; +} pmpdb_internal_t; + +typedef struct { + ip3db_t ip3db; +} pmppl_internal_t; + + +static uint32_t pmp_add_ref(pmp_t* pmp); +static uint32_t pmp_release(pmp_t* pmp); +static result_t pmp_create_instance_db(pmp_t* pmp, pmpdb_t** ptr_pmpdb); +static result_t pmp_create_instance_pl(pmp_t* pmp, pmppl_t** ptr_pmppl); +static result_t pmp_is_supported_codec(pmp_t* pmp, uint32_t codec); +static result_t pmp_is_supported_ext(pmp_t* pmp, const ucs2char_t* filename); + +static uint32_t pmpdb_add_ref(pmpdb_t* pmpdb); +static uint32_t pmpdb_release(pmpdb_t* pmpdb); +static result_t pmpdb_read(pmpdb_t* pmpdb); +static result_t pmpdb_write(pmpdb_t* pmpdb); +static result_t pmpdb_set(pmpdb_t* pmpdb, const pmp_record_t* records, uint32_t num_records); +static result_t pmpdb_get(pmpdb_t* pmpdb, pmp_record_t* records, uint32_t* num_records); +static result_t pmpdb_dump(pmpdb_t* pmpdb, FILE *fp, int level); + +static uint32_t pmppl_add_ref(pmppl_t* pmppl); +static uint32_t pmppl_release(pmppl_t* pmppl); +static result_t pmppl_write(pmppl_t* pmppl, const ucs2char_t* filename, ucs2char_t* const files[], uint32_t num_files); + + +static void set_environment( + ip3_environment_t* env, + const ip3model_descriptor_t* md, + const ucs2char_t* path_to_device + ) +{ + ucs2char_t* ucs2 = NULL; + + ucs2cpy(env->path_to_root, path_to_device); + + ucs2cpy(env->path_to_music, path_to_device); + filepath_addslash(env->path_to_music); + ucs2 = mbsdupucs2(md->path_to_music); + ucs2cat(env->path_to_music, ucs2); + ucs2free(ucs2); + + ucs2cpy(env->path_to_playlist, path_to_device); + filepath_addslash(env->path_to_playlist); + ucs2 = mbsdupucs2(md->path_to_playlist); + ucs2cat(env->path_to_playlist, ucs2); + ucs2free(ucs2); + + ucs2cpy(env->sys_filename, path_to_device); + filepath_addslash(env->sys_filename); + ucs2 = mbsdupucs2(md->sys_filename); + ucs2cat(env->sys_filename, ucs2); + ucs2free(ucs2); + + ucs2cpy(env->dat_filename, path_to_device); + filepath_addslash(env->dat_filename); + ucs2 = mbsdupucs2(md->dat_filename); + ucs2cat(env->dat_filename, ucs2); + ucs2free(ucs2); + + ucs2cpy(env->dic_filename, path_to_device); + filepath_addslash(env->dic_filename); + ucs2 = mbsdupucs2(md->dic_filename); + ucs2cat(env->dic_filename, ucs2); + ucs2free(ucs2); + + ucs2cpy(env->idx_filename, path_to_device); + filepath_addslash(env->idx_filename); + ucs2 = mbsdupucs2(md->idx_filename); + ucs2cat(env->idx_filename, ucs2); + ucs2free(ucs2); + + ucs2 = mbsdupucs2(md->playlist_ext); + ucs2cat(env->playlist_ext, ucs2); + ucs2free(ucs2); +} + +static int match_model( + const char *id, + const ucs2char_t* path_to_device, + const ip3model_descriptor_t* md, + ip3_environment_t* env + ) +{ + memset(env, 0, sizeof(*env)); + + if (!id || strcmp(md->id, id) != 0) { + return 0; + } + + set_environment(env, md, path_to_device); + return 1; +} + +static char* strip(char *str) +{ + char *p = str + strlen(str) - 1; + while (*str && isspace(*str)) { + str++; + } + while (str <= p && isspace(*p)) { + *p-- = 0; + } + return str; +} + +#define COMP(a, b) ((a)>(b))-((a)<(b)) + +static int compare_version(const char *x, const char *y) +{ + char *p = NULL, *q = NULL; + + for (;;) { + long a = strtol(x, &p, 10); + long b = strtol(y, &q, 10); + int value = COMP(a, b); + if (value != 0) { + return value; + } + if (!*p || !*q || *p != *q) { + return COMP(*p, *q); + } + x = p+1; + y = q+1; + } +} + +static int detect_model( + const ucs2char_t* path_to_device, + const ip3model_descriptor_t* md, + ip3_environment_t* env + ) +{ + ucs2char_t* ucs2 = NULL; + ucs2char_t filename[MAX_PATH]; + + memset(env, 0, sizeof(*env)); + + ucs2cpy(filename, path_to_device); + filepath_addslash(filename); + ucs2 = mbsdupucs2(md->sys_filename); + ucs2cat(filename, ucs2); + ucs2free(ucs2); + if (filepath_file_exists(filename)) { + int match = 1; + char line[128]; + FILE *fp = ucs2fopen(filename, "r"); + if (!fp) { + return 0; + } + + while (fgets(line, sizeof(line)-1, fp)) { + char *p = strip(line); + if (p[0] == '[' && line[strlen(p)-1] == ']') { + p[strlen(p)-1] = 0; + strcpy(env->name, p+1); + } else if (strncmp(p, "version = ", 10) == 0) { + /* They are too stupid to describe version "1.04" as "1.4" */ + if (strlen(p+10) == 3 && p[11] == '.') { + env->version[0] = p[10]; + env->version[1] = p[11]; + env->version[2] = '0'; + env->version[3] = p[12]; + env->version[4] = 0; + } else { + strcpy(env->version, p+10); + } + } else if (strncmp(p, "language = ", 11) == 0) { + strcpy(env->language, p+11); + } else if (strncmp(p, "mode = ", 7) == 0) { + strcpy(env->mode, p+7); + } + } + fclose(fp); + + match &= (strcmp(env->mode, md->mode) == 0); + match &= (compare_version(md->min_version, env->version) <= 0); + match &= (compare_version(env->version, md->max_version) <= 0); + + if (match) { + set_environment(env, md, path_to_device); + return 1; + } + } + return 0; +} + + + +PMPIRIVERPLUS3API result_t pmp_enumerate_devid(pmp_enumerate_devid_callback_t callback, void *instance) +{ + const ip3model_descriptor_t* md = g_model_descriptions; + for (;md->id;++md) { + callback(instance, md->id); + } + return 0; +} + +PMPIRIVERPLUS3API result_t pmp_create(pmp_t** ptr_pmp, const ucs2char_t* path_to_device, const char *id) +{ + result_t ret = 0; + pmp_t* pmp = NULL; + pmp_internal_t* pmpi = NULL; + const ip3model_descriptor_t* md = NULL; + ip3_environment_t env; + pmp_environment_t* pmpenv = NULL; + + *ptr_pmp = 0; + + // Find a suitable model for the device. + md = g_model_descriptions; + for (;md->id;++md) { + if (detect_model(path_to_device, md, &env)) { + if (!id || !id[0]) { + break; + } + if (strcmp(md->id, id) == 0) { + break; + } + } + if (match_model(id, path_to_device, md, &env)) { + break; + } + } + if (!md->id) { + return PMP_DEVICENOTFOUND; + } + + // Allocate PMP class instance. + pmp = (pmp_t*)calloc(1, sizeof(pmp_t)); + if (!pmp) { + return PMPDBE_OUTOFMEMORY; + } + + pmp->add_ref = pmp_add_ref; + pmp->release = pmp_release; + pmp->create_instance_db = pmp_create_instance_db; + pmp->create_instance_pl = pmp_create_instance_pl; + pmp->is_supported_codec = pmp_is_supported_codec; + pmp->is_supported_ext = pmp_is_supported_ext; + + // Allocate the internal variables. + pmpi = (pmp_internal_t*)calloc(1, sizeof(pmp_internal_t)); + if (!pmpi) { + free(pmp); + return PMPDBE_OUTOFMEMORY; + } + pmp->instance = pmpi; + + // Initialize the internal variables. + memcpy(&pmpi->env, &env, sizeof(env)); + + // Initialize the (exportable) env. + pmpenv = &pmp->env; + strcpy(pmpenv->id, md->id); + strcpy(pmpenv->name, md->name); + strcpy(pmpenv->mode, md->mode); + strcpy(pmpenv->language, pmpi->env.language); + strcpy(pmpenv->version, pmpi->env.version); + pmpenv->path_to_root.flag = PMPPEF_SUPPORT | PMPPEF_CONSTANT; + ucs2cpy(pmpenv->path_to_root.path, pmpi->env.path_to_root); + pmpenv->path_to_music.flag = PMPPEF_SUPPORT | PMPPEF_RECURSIVE; + ucs2cpy(pmpenv->path_to_music.path, pmpi->env.path_to_music); + pmpenv->path_to_playlist.flag = PMPPEF_SUPPORT; + ucs2cpy(pmpenv->path_to_playlist.path, pmpi->env.path_to_playlist); + ucs2cpy(pmpenv->playlist_ext, pmpi->env.playlist_ext); + + // Prepare + pmp->add_ref(pmp); + *ptr_pmp = pmp; + return 0; +} + +static uint32_t pmp_add_ref(pmp_t* pmp) +{ + return interlocked_increment(&pmp->ref_count); +} + +static uint32_t pmp_release(pmp_t* pmp) +{ + uint32_t count = interlocked_decrement(&pmp->ref_count); + if (count == 0) { + free(pmp->instance); + free(pmp); + } + return count; +} + +static result_t pmp_create_instance_db(pmp_t* pmp, pmpdb_t** ptr_pmpdb) +{ + pmpdb_t* pmpdb = NULL; + pmp_internal_t* pmpi = (pmp_internal_t*)pmp->instance; + pmpdb_internal_t* pmpdbi = NULL; + + *ptr_pmpdb = 0; + + pmpdb = calloc(1, sizeof(pmpdb_t)); + if (!pmpdb) { + return PMPDBE_OUTOFMEMORY; + } + + pmpdb->add_ref = pmpdb_add_ref; + pmpdb->release = pmpdb_release; + pmpdb->read = pmpdb_read; + pmpdb->write = pmpdb_write; + pmpdb->set = pmpdb_set; + pmpdb->get = pmpdb_get; + pmpdb->dump = pmpdb_dump; + + pmpdbi = calloc(1, sizeof(pmpdb_internal_t)); + if (!pmpdbi) { + free(pmpdb); + return PMPDBE_OUTOFMEMORY; + } + ip3db_init(&pmpdbi->ip3db); + + pmpdb->pmp = pmp; + pmpdb->instance = pmpdbi; + + pmpdb->add_ref(pmpdb); + *ptr_pmpdb = pmpdb; + return 0; +} + +static result_t pmp_create_instance_pl(pmp_t* pmp, pmppl_t** ptr_pmppl) +{ + pmp_internal_t* pmpi = (pmp_internal_t*)pmp->instance; + pmppl_t* pmppl = NULL; + pmppl_internal_t* pmppli = NULL; + + *ptr_pmppl = 0; + return PMP_NOTIMPLIMENTED; +} + + + +static int pmp_is_supported_codec(pmp_t* pmp, uint32_t codec) +{ + return ( + (codec == PMPCODEC_MPEGLAYER3) || + (codec == PMPCODEC_WMA) || + (codec == PMPCODEC_VORBIS) + ) ? 1 : 0; +} + +static int pmp_is_supported_ext(pmp_t* pmp, const ucs2char_t* filename) +{ + static const ucs2char_t ucs2cs_mp3[] = {'.','m','p','3',0}; + static const ucs2char_t ucs2cs_wma[] = {'.','w','m','a',0}; + static const ucs2char_t ucs2cs_ogg[] = {'.','o','g','g',0}; + + return ( + filepath_hasext(filename, ucs2cs_mp3) || + filepath_hasext(filename, ucs2cs_wma) || + filepath_hasext(filename, ucs2cs_ogg) + ) ? 1 : 0; +} + + + + + +static uint32_t pmpdb_add_ref(pmpdb_t* pmpdb) +{ + return interlocked_increment(&pmpdb->ref_count); +} + +static uint32_t pmpdb_release(pmpdb_t* pmpdb) +{ + uint32_t count = interlocked_decrement(&pmpdb->ref_count); + if (count == 0) { + pmpdb_internal_t* pmpdbi = (pmpdb_internal_t*)pmpdb->instance; + ip3db_finish(&pmpdbi->ip3db); + free(pmpdb->instance); + free(pmpdb); + } + return count; +} + +static result_t pmpdb_read(pmpdb_t* pmpdb) +{ + pmpdb_internal_t* pmpdbi = (pmpdb_internal_t*)pmpdb->instance; + pmp_internal_t* pmpi = (pmp_internal_t*)pmpdb->pmp->instance; + return ip3db_read( + &pmpdbi->ip3db, + pmpi->env.dat_filename, + pmpi->env.dic_filename, + pmpi->env.idx_filename + ); +} + +static result_t pmpdb_write(pmpdb_t* pmpdb) +{ + pmpdb_internal_t* pmpdbi = (pmpdb_internal_t*)pmpdb->instance; + pmp_internal_t* pmpi = (pmp_internal_t*)pmpdb->pmp->instance; + return PMP_NOTIMPLIMENTED; + //return ip2db_write(&pmpdbi->ip2db, pmpi->env.dat_filename, pmpi->env.idx_filename); +} + +static result_t pmpdb_set(pmpdb_t* pmpdb, const pmp_record_t* records, uint32_t num_records) +{ + pmpdb_internal_t* pmpdbi = (pmpdb_internal_t*)pmpdb->instance; + pmp_internal_t* pmpi = (pmp_internal_t*)pmpdb->pmp->instance; + return PMP_NOTIMPLIMENTED; + //return ip2db_set(&pmpdbi->ip2db, records, num_records, pmpi->env.path_to_root); +} + +static result_t pmpdb_get(pmpdb_t* pmpdb, pmp_record_t* records, uint32_t* num_records) +{ + pmpdb_internal_t* pmpdbi = (pmpdb_internal_t*)pmpdb->instance; + pmp_internal_t* pmpi = (pmp_internal_t*)pmpdb->pmp->instance; + return PMP_NOTIMPLIMENTED; + //return ip2db_get(&pmpdbi->ip2db, records, num_records, pmpi->env.path_to_root); +} + +static result_t pmpdb_dump(pmpdb_t* pmpdb, FILE *fp, int level) +{ + pmpdb_internal_t* pmpdbi = (pmpdb_internal_t*)pmpdb->instance; + if (level > 0) { + return PMP_NOTIMPLIMENTED; + //return ip2db_repr(&pmpdbi->ip2db, fp); + } else { + return ip3db_dump(&pmpdbi->ip3db, fp); + } +} + + + + +static uint32_t pmppl_add_ref(pmppl_t* pmppl) +{ + return interlocked_increment(&pmppl->ref_count); +} + +static uint32_t pmppl_release(pmppl_t* pmppl) +{ + uint32_t count = interlocked_decrement(&pmppl->ref_count); + if (count == 0) { + pmppl_internal_t* pmppli = (pmppl_internal_t*)pmppl->instance; + free(pmppl->instance); + free(pmppl); + } + return count; +} + +static result_t pmppl_write(pmppl_t* pmppl, const ucs2char_t* filename, ucs2char_t* const files[], uint32_t num_files) +{ + pmppl_internal_t* pmppli = (pmppl_internal_t*)pmppl->instance; + pmp_internal_t* pmpi = (pmp_internal_t*)pmppl->pmp->instance; + return PMP_NOTIMPLIMENTED; + /* + if (ip2db_playlist_write(&pmppli->ip2db, filename, files, num_files, pmpi->env.path_to_root) != 0) { + return PMPPLE_WRITE; + } + return 0; + */ +} Property changes on: trunk/pmplib/lib/pmp_iriverplus3/pmp_iriverplus3.c ___________________________________________________________________ Name: svn:keywords + Id Modified: trunk/pmplib/lib/pmp_iriverplus3/pmp_iriverplus3.vcproj =================================================================== --- trunk/pmplib/lib/pmp_iriverplus3/pmp_iriverplus3.vcproj 2006-12-24 02:42:41 UTC (rev 194) +++ trunk/pmplib/lib/pmp_iriverplus3/pmp_iriverplus3.vcproj 2006-12-24 05:09:19 UTC (rev 195) @@ -17,7 +17,7 @@ <Configurations> <Configuration Name="Debug|Win32" - OutputDirectory="$(SolutionDir)$(ConfigurationName)" + OutputDirectory="$(SolutionDir)debug" IntermediateDirectory="$(ConfigurationName)" ConfigurationType="2" CharacterSet="1" @@ -193,6 +193,10 @@ > </File> <File + RelativePath=".\pmp_iriverplus3.c" + > + </File> + <File RelativePath=".\serialize.c" > </File> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |