1 /* COPYRIGHT: See COPYING in the top level directory
2 * PROJECT: ReactOS system libraries
3 * FILE: lib/rtl/dos8dot3.c
4 * PURPOSE: Short name (8.3 name) functions
5 * PROGRAMMER: Eric Kohl
8 /* INCLUDES ******************************************************************/
16 /* CONSTANTS *****************************************************************/
18 const PCHAR RtlpShortIllegals
= " ;+=[],\"*\\<>/?:|";
21 /* FUNCTIONS *****************************************************************/
24 RtlpIsShortIllegal(CHAR Char
)
26 return strchr(RtlpShortIllegals
, Char
) ? TRUE
: FALSE
;
30 RtlpGetCheckSum(PUNICODE_STRING Name
)
36 Length
= Name
->Length
/ sizeof(WCHAR
);
40 Hash
= (Hash
+ (*c
<< 4) + (*c
>> 4)) * 11;
47 RtlpGetIndexLength(ULONG Index
)
55 return Length
? Length
: 1;
63 RtlGenerate8dot3Name(IN PUNICODE_STRING Name
,
64 IN BOOLEAN AllowExtendedCharacters
,
65 IN OUT PGENERATE_NAME_CONTEXT Context
,
66 OUT PUNICODE_STRING Name8dot3
)
82 StrLength
= Name
->Length
/ sizeof(WCHAR
);
83 DPRINT("StrLength: %lu\n", StrLength
);
85 /* Find last dot in Name */
87 for (i
= 0; i
< StrLength
; i
++)
89 if (Name
->Buffer
[i
] == L
'.')
99 DPRINT("DotPos: %lu\n", DotPos
);
101 /* Copy name (6 valid characters max) */
102 for (i
= 0, NameLength
= 0; NameLength
< 6 && i
< DotPos
; i
++)
105 RtlUpcaseUnicodeToOemN(&c
, sizeof(CHAR
), &Count
, &Name
->Buffer
[i
], sizeof(WCHAR
));
106 if (Count
!= 1 || c
== 0 || RtlpIsShortIllegal(c
))
108 NameBuffer
[NameLength
++] = L
'_';
112 NameBuffer
[NameLength
++] = (WCHAR
)c
;
116 DPRINT("NameBuffer: '%.08S'\n", NameBuffer
);
117 DPRINT("NameLength: %lu\n", NameLength
);
119 /* Copy extension (4 valid characters max) */
120 if (DotPos
< StrLength
)
122 for (i
= DotPos
, ExtLength
= 0; ExtLength
< 4 && i
< StrLength
; i
++)
125 RtlUpcaseUnicodeToOemN(&c
, sizeof(CHAR
), &Count
, &Name
->Buffer
[i
], sizeof(WCHAR
));
126 if (Count
!= 1 || c
== 0 || RtlpIsShortIllegal(Name
->Buffer
[i
]))
128 ExtBuffer
[ExtLength
++] = L
'_';
132 ExtBuffer
[ExtLength
++] = c
;
140 DPRINT("ExtBuffer: '%.04S'\n", ExtBuffer
);
141 DPRINT("ExtLength: %lu\n", ExtLength
);
143 /* Determine next index */
144 IndexLength
= RtlpGetIndexLength(Context
->LastIndexValue
);
145 if (Context
->CheckSumInserted
)
147 CopyLength
= min(NameLength
, 8 - 4 - 1 - IndexLength
);
148 Checksum
= RtlpGetCheckSum(Name
);
152 CopyLength
= min(NameLength
, 8 - 1 - IndexLength
);
156 DPRINT("CopyLength: %lu\n", CopyLength
);
158 if ((Context
->NameLength
== CopyLength
) &&
159 (wcsncmp(Context
->NameBuffer
, NameBuffer
, CopyLength
) == 0) &&
160 (Context
->ExtensionLength
== ExtLength
) &&
161 (wcsncmp(Context
->ExtensionBuffer
, ExtBuffer
, ExtLength
) == 0) &&
162 (Checksum
== Context
->Checksum
) &&
163 (Context
->LastIndexValue
< 999))
165 Context
->LastIndexValue
++;
166 if (Context
->CheckSumInserted
== FALSE
&&
167 Context
->LastIndexValue
> 9)
169 Context
->CheckSumInserted
= TRUE
;
170 Context
->LastIndexValue
= 1;
171 Context
->Checksum
= RtlpGetCheckSum(Name
);
176 Context
->LastIndexValue
= 1;
177 Context
->CheckSumInserted
= FALSE
;
180 IndexLength
= RtlpGetIndexLength(Context
->LastIndexValue
);
182 DPRINT("CurrentIndex: %lu, IndexLength %lu\n", Context
->LastIndexValue
, IndexLength
);
184 if (Context
->CheckSumInserted
)
186 CopyLength
= min(NameLength
, 8 - 4 - 1 - IndexLength
);
190 CopyLength
= min(NameLength
, 8 - 1 - IndexLength
);
193 /* Build the short name */
194 memcpy(Name8dot3
->Buffer
, NameBuffer
, CopyLength
* sizeof(WCHAR
));
196 if (Context
->CheckSumInserted
)
199 Checksum
= Context
->Checksum
;
200 for (i
= 0; i
< 4; i
++)
202 Name8dot3
->Buffer
[j
--] = (Checksum
% 16) > 9 ? (Checksum
% 16) + L
'A' - 10 : (Checksum
% 16) + L
'0';
207 Name8dot3
->Buffer
[j
++] = L
'~';
208 j
+= IndexLength
- 1;
209 CurrentIndex
= Context
->LastIndexValue
;
210 for (i
= 0; i
< IndexLength
; i
++)
212 Name8dot3
->Buffer
[j
--] = (CurrentIndex
% 10) + L
'0';
215 j
+= IndexLength
+ 1;
217 memcpy(Name8dot3
->Buffer
+ j
, ExtBuffer
, ExtLength
* sizeof(WCHAR
));
218 Name8dot3
->Length
= (j
+ ExtLength
) * sizeof(WCHAR
);
220 DPRINT("Name8dot3: '%wZ'\n", Name8dot3
);
223 Context
->NameLength
= CopyLength
;
224 Context
->ExtensionLength
= ExtLength
;
225 memcpy(Context
->NameBuffer
, NameBuffer
, CopyLength
* sizeof(WCHAR
));
226 memcpy(Context
->ExtensionBuffer
, ExtBuffer
, ExtLength
* sizeof(WCHAR
));
235 RtlIsNameLegalDOS8Dot3(IN PCUNICODE_STRING UnicodeName
,
236 IN OUT POEM_STRING AnsiName OPTIONAL
,
237 IN OUT PBOOLEAN SpacesFound OPTIONAL
)
239 static const char Illegal
[] = "*?<>|\"+=,;[]:/\\\345";
243 OEM_STRING OemString
;
244 BOOLEAN GotSpace
= FALSE
;
248 OemString
.Length
= sizeof(Buffer
);
249 OemString
.MaximumLength
= sizeof(Buffer
);
250 OemString
.Buffer
= Buffer
;
251 AnsiName
= &OemString
;
253 if (RtlUpcaseUnicodeStringToCountedOemString( AnsiName
, UnicodeName
, FALSE
) != STATUS_SUCCESS
)
256 if ((AnsiName
->Length
> 12) || (AnsiName
->Buffer
== NULL
)) return FALSE
;
258 /* a starting . is invalid, except for . and .. */
259 if (AnsiName
->Buffer
[0] == '.')
261 if (AnsiName
->Length
!= 1 && (AnsiName
->Length
!= 2 || AnsiName
->Buffer
[1] != '.')) return FALSE
;
262 if (SpacesFound
) *SpacesFound
= FALSE
;
266 for (i
= 0; i
< AnsiName
->Length
; i
++)
268 switch (AnsiName
->Buffer
[i
])
271 /* leading/trailing spaces not allowed */
272 if (!i
|| i
== AnsiName
->Length
-1 || AnsiName
->Buffer
[i
+1] == '.') return FALSE
;
276 if (Dot
!= -1) return FALSE
;
280 if (strchr(Illegal
, AnsiName
->Buffer
[i
])) return FALSE
;
284 /* check file part is shorter than 8, extension shorter than 3
285 * dot cannot be last in string
289 if (AnsiName
->Length
> 8) return FALSE
;
293 if (Dot
> 8 || (AnsiName
->Length
- Dot
> 4) || Dot
== AnsiName
->Length
- 1) return FALSE
;
295 if (SpacesFound
) *SpacesFound
= GotSpace
;
304 RtlVolumeDeviceToDosName(
305 IN PVOID VolumeDeviceObject
,
306 OUT PUNICODE_STRING DosName
310 return STATUS_NOT_IMPLEMENTED
;