714
// In Windows we need to check if all file name characters are defined
715
// in current code page. For example, in Korean CP949 a lot of high ASCII
716
// characters are not defined, cannot be used in file names, but cannot be
717
// detected by other checks in this function.
718
if (MultiByteToWideChar(CP_ACP,MB_ERR_INVALID_CHARS,Name,-1,NULL,0)==0 &&
719
GetLastError()==ERROR_NO_UNICODE_TRANSLATION)
702
722
return(*Name!=0 && strpbrk(Name,"?*<>|\"")==NULL);
726
bool IsNameUsable(const wchar *Name)
729
if (Name[0] && Name[1] && wcschr(Name+2,':')!=NULL)
731
for (const wchar *s=Name;*s!=0;s++)
735
if (*s==' ' && IsPathDiv(s[1]))
739
return(*Name!=0 && wcspbrk(Name,L"?*<>|\"")==NULL);
706
743
void MakeNameUsable(char *Name,bool Extended)
746
// In Windows we also need to convert characters not defined in current
747
// code page. This double conversion changes them to '?', which is
748
// catched by code below.
749
size_t NameLength=strlen(Name);
751
CharToWide(Name,NameW,ASIZE(NameW));
752
WideToChar(NameW,Name,NameLength+1);
708
755
for (char *s=Name;*s!=0;s=charnext(s))
710
757
if (strchr(Extended ? "?*<>|\"":"?*",*s)!=NULL || Extended && (byte)*s<32)
1176
static void GenArcName(char *ArcName,wchar *ArcNameW,char *GenerateMask,
1177
uint ArcNumber,bool &ArcNumPresent);
1179
void GenerateArchiveName(char *ArcName,wchar *ArcNameW,size_t MaxSize,
1180
char *GenerateMask,bool Archiving)
1182
// Must be enough space for archive name plus all stuff in mask plus
1183
// extra overhead produced by mask 'N' (archive number) characters.
1184
// One 'N' character can result in several numbers if we process more
1186
char NewName[NM+MAX_GENERATE_MASK+20];
1187
wchar NewNameW[NM+MAX_GENERATE_MASK+20];
1190
while (true) // Loop for 'N' (archive number) processing.
1192
strncpyz(NewName,NullToEmpty(ArcName),ASIZE(NewName));
1193
wcsncpyz(NewNameW,NullToEmpty(ArcNameW),ASIZE(NewNameW));
1195
bool ArcNumPresent=false;
1197
GenArcName(NewName,NewNameW,GenerateMask,ArcNumber,ArcNumPresent);
1201
if (!FileExist(NewName,NewNameW))
1203
if (!Archiving && ArcNumber>1)
1205
// If we perform non-archiving operation, we need to use the last
1206
// existing archive before the first unused name. So we generate
1207
// the name for (ArcNumber-1) below.
1208
strncpyz(NewName,NullToEmpty(ArcName),ASIZE(NewName));
1209
wcsncpyz(NewNameW,NullToEmpty(ArcNameW),ASIZE(NewNameW));
1210
GenArcName(NewName,NewNameW,GenerateMask,ArcNumber-1,ArcNumPresent);
1216
if (ArcName!=NULL && *ArcName!=0)
1217
strncpyz(ArcName,NewName,MaxSize);
1218
if (ArcNameW!=NULL && *ArcNameW!=0)
1219
wcsncpyz(ArcNameW,NewNameW,MaxSize);
1223
void GenArcName(char *ArcName,wchar *ArcNameW,char *GenerateMask,
1224
uint ArcNumber,bool &ArcNumPresent)
1227
if (*GenerateMask=='+')
1229
Prefix=true; // Add the time string before the archive name.
1230
GenerateMask++; // Skip '+' in the beginning of time mask.
1233
char Mask[MAX_GENERATE_MASK];
1234
strncpyz(Mask,*GenerateMask ? GenerateMask:"yyyymmddhhmmss",ASIZE(Mask));
1236
bool QuoteMode=false,Hours=false;
1237
for (uint I=0;Mask[I]!=0;I++)
1239
if (Mask[I]=='{' || Mask[I]=='}')
1241
QuoteMode=(Mask[I]=='{');
1246
int CurChar=etoupper(Mask[I]);
1250
if (Hours && CurChar=='M')
1252
// Replace minutes with 'I'. We use 'M' both for months and minutes,
1253
// so we treat as minutes only those 'M' which are found after hours.
1258
uint Digits=GetDigits(ArcNumber);
1260
while (etoupper(Mask[I+NCount])=='N')
1263
// Here we ensure that we have enough 'N' characters to fit all digits
1264
// of archive number. We'll replace them by actual number later
1265
// in this function.
1268
memmove(Mask+I+Digits,Mask+I+NCount,strlen(Mask+I+NCount)+1);
1269
memset(Mask+I,'N',Digits);
1271
I+=Max(Digits,NCount)-1;
1278
CurTime.SetCurrentTime();
1280
CurTime.GetLocal(&rlt);
1284
if (ArcName!=NULL && *ArcName!=0)
1287
if ((Dot=GetExt(ArcName))==NULL)
1288
strcpy(Ext,*PointToName(ArcName)==0 ? ".rar":"");
1298
if (ArcNameW!=NULL && *ArcNameW!=0)
1301
if ((DotW=GetExt(ArcNameW))==NULL)
1302
wcscpy(ExtW,*PointToName(ArcNameW)==0 ? L".rar":L"");
1310
int WeekDay=rlt.wDay==0 ? 6:rlt.wDay-1;
1311
int StartWeekDay=rlt.yDay-WeekDay;
1313
if (StartWeekDay<=-4)
1314
StartWeekDay+=IsLeapYear(rlt.Year-1) ? 366:365;
1317
int CurWeek=StartWeekDay/7+1;
1318
if (StartWeekDay%7>=4)
1323
sprintf(Field[0],"%04d",rlt.Year);
1324
sprintf(Field[1],"%02d",rlt.Month);
1325
sprintf(Field[2],"%02d",rlt.Day);
1326
sprintf(Field[3],"%02d",rlt.Hour);
1327
sprintf(Field[4],"%02d",rlt.Minute);
1328
sprintf(Field[5],"%02d",rlt.Second);
1329
sprintf(Field[6],"%02d",CurWeek);
1330
sprintf(Field[7],"%d",WeekDay+1);
1331
sprintf(Field[8],"%03d",rlt.yDay+1);
1332
sprintf(Field[9],"%05d",ArcNumber);
1334
const char *MaskChars="YMDHISWAEN";
1336
int CField[sizeof(Field)/sizeof(Field[0])];
1337
memset(CField,0,sizeof(CField));
1339
for (int I=0;Mask[I]!=0;I++)
1341
if (Mask[I]=='{' || Mask[I]=='}')
1343
QuoteMode=(Mask[I]=='{');
1348
const char *Ch=strchr(MaskChars,etoupper(Mask[I]));
1350
CField[Ch-MaskChars]++;
1353
char DateText[MAX_GENERATE_MASK];
1356
for (size_t I=0,J=0;Mask[I]!=0 && J<ASIZE(DateText)-1;I++)
1358
if (Mask[I]=='{' || Mask[I]=='}')
1360
QuoteMode=(Mask[I]=='{');
1363
const char *Ch=strchr(MaskChars,etoupper(Mask[I]));
1364
if (Ch==NULL || QuoteMode)
1365
DateText[J]=Mask[I];
1368
size_t FieldPos=Ch-MaskChars;
1369
int CharPos=(int)strlen(Field[FieldPos])-CField[FieldPos]--;
1370
if (FieldPos==1 && etoupper(Mask[I+1])=='M' && etoupper(Mask[I+2])=='M')
1372
strncpyz(DateText+J,GetMonthName(rlt.Month-1),ASIZE(DateText)-J);
1378
DateText[J]=Mask[I];
1380
DateText[J]=Field[FieldPos][CharPos];
1385
wchar DateTextW[ASIZE(DateText)];
1386
CharToWide(DateText,DateTextW);
1390
if (ArcName!=NULL && *ArcName!=0)
1393
GetFilePath(ArcName,NewName,ASIZE(NewName));
1394
AddEndSlash(NewName);
1395
strcat(NewName,DateText);
1396
strcat(NewName,PointToName(ArcName));
1397
strcpy(ArcName,NewName);
1399
if (ArcNameW!=NULL && *ArcNameW!=0)
1402
GetFilePath(ArcNameW,NewNameW,ASIZE(NewNameW));
1403
AddEndSlash(NewNameW);
1404
wcscat(NewNameW,DateTextW);
1405
wcscat(NewNameW,PointToName(ArcNameW));
1406
wcscpy(ArcNameW,NewNameW);
1411
if (ArcName!=NULL && *ArcName!=0)
1412
strcat(ArcName,DateText);
1413
if (ArcNameW!=NULL && *ArcNameW!=0)
1414
wcscat(ArcNameW,DateTextW);
1416
if (ArcName!=NULL && *ArcName!=0)
1417
strcat(ArcName,Ext);
1418
if (ArcNameW!=NULL && *ArcNameW!=0)
1419
wcscat(ArcNameW,ExtW);
1108
1424
wchar* GetWideName(const char *Name,const wchar *NameW,wchar *DestW,size_t DestSize)