#include "names.h"
#include "file_info.h"
#include <string.h>
#include <ctype.h>
#define ustrchr(s, c) (unsigned char *)strchr((const char *)s, c)
#define ustrrchr(s, c) (unsigned char *)strrchr((const char *)s, c)
static inline int isvalid(unsigned char c)
{
return isalnum(c) || c > 127 || (c && strchr("$%'-_@~(){}^#&", c));
}
static void decode(const unsigned char shortname[], unsigned char buffer[])
{
unsigned char *pd;
pd = buffer;
memcpy(pd, shortname, 8);
pd[8] = ' ';
pd = ustrchr(pd, ' ');
if (shortname[8] != ' ') {
*pd++ = '.';
memcpy(pd, shortname + 8, 3);
pd[3] = ' ';
pd = ustrchr(pd, ' ');
}
*pd = '\0';
}
static int fit(const unsigned short *longname, const unsigned char shortname[])
{
unsigned char buffer[13];
unsigned char *pb;
decode(shortname, pb = buffer);
do {
if (*pb != *longname)
return 0;
if (!*pb)
return 1;
pb++;
longname++;
}
while (1);
}
static int ifit(const unsigned short *longname, const unsigned char shortname[])
{
unsigned char buffer[13];
unsigned char *pb;
decode(shortname, pb = buffer);
while (*pb && *longname && toupper(*pb++) == toupper(*longname++));
return !*pb && !*longname;
}
static int collide(const struct file_info_struct *dir_info)
{
unsigned int i;
for (i = 0; i < dir_info->count - 1; i++)
if (!memcmp(dir_info->entries[dir_info->count - 1].shortname,
dir_info->entries[i].shortname, 11))
return 1;
return 0;
}
static void insert_numerictail(unsigned char shortname[], unsigned int n)
{
unsigned char buffer[8];
unsigned char *pd;
unsigned int i;
for (i = 7; n && i > 0; i--) {
buffer[i] = (n % 10) + '0';
n /= 10;
}
buffer[i] = '~';
pd = shortname;
while (*pd != ' ' && pd < shortname + i)
pd++;
memcpy(pd, buffer + i, 8 - i);
}
static void generate_basisname(const unsigned short *longname, unsigned char shortname[], int *lossy_conversion)
{
unsigned char buffer[256];
const unsigned short *pss;
const unsigned char *ps;
unsigned char *pd;
unsigned int i;
*lossy_conversion = 0;
memset(shortname, ' ', 11);
pss = longname;
pd = buffer;
do
*pd++ = toupper((unsigned char)*pss);
while (*pss++ && (size_t)(pd - buffer) < sizeof buffer - 1);
buffer[sizeof buffer - 1] = '\0';
for (pd = buffer; *pd; pd++)
if (!isvalid(*pd) && *pd != ' ' && *pd != '.') {
*pd = '_';
*lossy_conversion = 1;
}
ps = pd = buffer;
do
if (*ps != ' ')
*pd++ = *ps;
while (*ps++);
ps = pd = buffer;
while (*ps == '.')
ps++;
do
*pd++ = *ps;
while (*ps++);
ps = buffer;
pd = shortname;
i = 0;
while (*ps && *ps != '.' && i++ < 8)
*pd++ = *ps++;
ps = ustrrchr(buffer, '.');
if (ps && *++ps) {
pd = shortname + 8;
i = 0;
while (*ps && i++ < 3)
*pd++ = *ps++;
}
}
static void generate_numerictail(struct file_info_struct *dir_info, int lossy_conversion)
{
unsigned int n;
if (!lossy_conversion
&& ifit(dir_info->entries[dir_info->count - 1].longname, dir_info->entries[dir_info->count - 1].shortname)
&& !collide(dir_info))
return;
n = 1;
do
insert_numerictail(dir_info->entries[dir_info->count - 1].shortname, n++);
while (collide(dir_info));
}
void generate_longname(struct file_info_struct *dir_info)
{
unsigned int i;
for (i = 0; dir_info->entries[dir_info->count - 1].filename[i] && i < 255; i++)
dir_info->entries[dir_info->count - 1].longname[i] = dir_info->entries[dir_info->count - 1].filename[i];
dir_info->entries[dir_info->count - 1].longname[i] = '\0';
}
void generate_shortname(struct file_info_struct *dir_info)
{
int lossy_conversion;
generate_basisname(dir_info->entries[dir_info->count - 1].longname,
dir_info->entries[dir_info->count - 1].shortname,
&lossy_conversion);
generate_numerictail(dir_info, lossy_conversion);
}
unsigned int n_long_entries(const struct file_info_struct *file_info)
{
unsigned int len;
for (len = 0; file_info->longname[len]; len++);
return fit(file_info->longname, file_info->shortname) ? 0 : (len + 12) / 13;
}