#include "vfat_collide.h"
#include <segment.h>
#include <errno.h>
#include <sprintf.h>
#include <string.h>
#include <ctype.h>
static inline int isvalid_short(unsigned char c)
{
return isalnum(c) || c > 127 || strchr("$%'-_@~(){}^#&", c);
}
static inline int isvalid_long(unsigned short c)
{
return c > 255 || isvalid_short(c) || strchr(". +,;=[]", c);
}
static void decode_shortname(const unsigned char shortname[], unsigned char buffer[])
{
int n, l, i;
buffer[0] = shortname[0] == 0x05 ? 0xe5 : shortname[0];
n = 1;
l = shortname[0] != ' ' ? 1 : 0;
i = 1;
while (i < 8)
if ((buffer[n++] = shortname[i++]) != ' ')
l = n;
if (shortname[8] != ' ') {
buffer[n = l, n++] = '.';
while (i < 11)
if ((buffer[n++] = shortname[i++]) != ' ')
l = n;
}
buffer[l] = '\0';
}
static void generate_basisname(const unsigned short *longname, unsigned char shortname[], int *lossy_conversion)
{
unsigned char *p;
int n;
unsigned short c;
*lossy_conversion = 0;
p = shortname;
n = 0;
while ((c = toupper(*longname++))) {
if (c == ' ')
continue;
if (p == shortname) {
if (c == '.') {
if (n == 0)
continue;
while (n < 8)
p[n++] = ' ';
p += 8;
n = 0;
continue;
}
if (n == 8)
continue;
}
else {
if (c == '.') {
n = 0;
continue;
}
if (n == 3)
continue;
}
if (c > 255 || !isvalid_short(c)) {
c = '_';
*lossy_conversion = 1;
}
p[n++] = c;
}
while (&p[n] < shortname + 11)
p[n++] = ' ';
}
static int fit(const unsigned short *longname, const unsigned char shortname[])
{
unsigned char buf[13];
int i;
decode_shortname(shortname, buf);
for (i = 0; buf[i]; i++)
if (*longname++ != buf[i])
return 0;
return !*longname;
}
static void insert_numerictail(unsigned char shortname[], unsigned int n)
{
unsigned char buf[8];
unsigned char *p;
int l;
buf[0] = '~';
l = 1 + snprintf((char *)(buf + 1), 7, "%u", n);
p = shortname;
while (*p != ' ' && p < shortname + 8 - l)
p++;
memcpy(p, buf, l);
}
static int generate_numerictail(const unsigned short *longname, unsigned char shortname[], int lossy_conversion, struct vfat_collide_fo_struct *collide_fo)
{
int n;
unsigned char primary[8];
int rv;
if (!lossy_conversion && fit(longname, shortname)) {
if ((rv = collide_fo->vptr->collide(collide_fo, shortname)) < 0)
return rv;
if (!rv)
return 0;
}
n = 1;
memcpy(primary, shortname, 8);
do {
if (n > 999999)
return -EINVAL;
memcpy(shortname, primary, 8);
insert_numerictail(shortname, n++);
if ((rv = collide_fo->vptr->collide(collide_fo, shortname)) < 0)
return rv;
}
while (rv);
return 0;
}
static int generate_longname(const char *fs_basename, unsigned short longname[])
{
int n;
int spaces;
unsigned short c;
n = 0;
spaces = 0;
while (c = get_fs_byte(fs_basename++), c && c != '/') {
if (c == ' ') {
if (n == 0)
continue;
spaces++;
}
else if (c == '.')
spaces++;
else if (!isvalid_long(c))
return -EINVAL;
else
spaces = 0;
if (n > 255)
return -ENAMETOOLONG;
longname[n++] = c;
}
if (n > 255)
return -ENAMETOOLONG;
longname[n - spaces] = '\0';
return 0;
}
static int generate_shortname(const unsigned short *longname, unsigned char shortname[], struct vfat_collide_fo_struct *collide_fo)
{
int lossy_conversion;
generate_basisname(longname, shortname, &lossy_conversion);
return generate_numerictail(longname, shortname, lossy_conversion, collide_fo);
}
int vfat_match_long(const char *fs_basename, const unsigned short *longname)
{
unsigned short c;
while (*longname == ' ')
longname++;
while (c = get_fs_byte(fs_basename++), c && c != '/')
if (toupper(c) != toupper(*longname++))
return 0;
while (*longname == ' ' || *longname == '.')
longname++;
return !*longname;
}
int vfat_match_short(const char *fs_basename, const unsigned char shortname[])
{
unsigned char buf[13];
int i;
decode_shortname(shortname, buf);
for (i = 0; buf[i]; i++)
if (toupper((unsigned char)get_fs_byte(fs_basename++)) != toupper(buf[i]))
return 0;
if (!strchr((char *)buf, '.') && get_fs_byte(fs_basename) == '.')
fs_basename++;
return !get_fs_byte(fs_basename) || get_fs_byte(fs_basename) == '/';
}
void vfat_decode_longname(const unsigned short longname[], char name[])
{
int i;
i = 0;
do
name[i++] = *longname < 256 ? *longname : '_';
while (*longname++);
}
void vfat_decode_shortname(const unsigned char shortname[], char name[])
{
decode_shortname(shortname, (unsigned char *)name);
}
int vfat_generate_names(const char *fs_basename, unsigned short longname[], unsigned char shortname[], struct vfat_collide_fo_struct *collide_fo)
{
int rv;
if ((rv = generate_longname(fs_basename, longname)) < 0)
return rv;
if ((rv = generate_shortname(longname, shortname, collide_fo)) < 0)
return rv;
return 0;
}
int vfat_fit(const unsigned short *longname, const unsigned char shortname[])
{
return fit(longname, shortname);
}