544 } |
559 } |
545 |
560 |
546 |
561 |
547 } |
562 } |
548 |
563 |
549 void TFatDirEntry::InitializeAsVFat(TUint8 aCheckSum) |
564 |
550 // |
565 //----------------------------------------------------------------------------- |
551 // Initialize a FAT entry as a VFAT filename |
566 /** |
552 // |
567 Write up to KMaxVFatEntryName unicode chars from aName to the entry |
553 { |
568 @param aName long file name part that will be converted into the VFAT entryset |
554 |
569 @param aLen length of the remaining name |
555 Mem::Fill(this,sizeof(SFatDirEntry),0xFF); |
570 @param aCheckSum DOS entry name checksum. |
|
571 */ |
|
572 void TFatDirEntry::SetVFatEntry(const TDesC& aName, TUint aLen, TUint8 aCheckSum) |
|
573 { |
|
574 //-- LFN in the last entry must be padded with FFs |
|
575 Mem::Fill(iData,sizeof(iData),0xFF); |
|
576 |
|
577 //-- initialise some VFAT entry specific fields |
556 iData[0x0B]=0x0F; |
578 iData[0x0B]=0x0F; |
557 iData[0x0C]=0x00; iData[0x0D]=aCheckSum; |
579 iData[0x0C]=0x00; iData[0x0D]=aCheckSum; |
558 iData[0x1A]=0x00; iData[0x1B]=0x00; |
580 iData[0x1A]=0x00; iData[0x1B]=0x00; |
559 } |
|
560 |
|
561 void TFatDirEntry::SetVFatEntry(const TDesC& aName,TInt aLen) |
|
562 // |
|
563 // Write up to KMaxVFatEntryName unicode chars from aName to the entry |
|
564 // |
|
565 { |
|
566 |
581 |
567 TInt rem=aName.Length()-aLen; |
582 TInt rem=aName.Length()-aLen; |
568 TPtrC section(aName.Ptr()+aLen,Min(rem,KMaxVFatEntryName)); |
583 TPtrC section(aName.Ptr()+aLen,Min(rem,KMaxVFatEntryName)); |
569 TBuf16<KMaxVFatEntryName> buf16; |
584 TBuf16<KMaxVFatEntryName> buf16; |
570 buf16.Copy(section); |
585 buf16.Copy(section); |
|
586 |
571 if (rem<KMaxVFatEntryName) |
587 if (rem<KMaxVFatEntryName) |
572 { |
588 { |
573 rem++; |
589 rem++; |
574 buf16.ZeroTerminate(); |
590 buf16.ZeroTerminate(); |
575 buf16.SetLength(rem); // Zero termination doesn't increase the buf length |
591 buf16.SetLength(rem); // Zero termination doesn't increase the buf length |
576 } |
592 } |
|
593 |
577 TUint8 orderNo=(TUint8)(aLen/KMaxVFatEntryName+1); |
594 TUint8 orderNo=(TUint8)(aLen/KMaxVFatEntryName+1); |
578 TInt s=Min(rem,5); |
595 TInt s=Min(rem,5); |
579 Mem::Copy(&iData[0x01],buf16.Ptr(),s*2);//Copy up to 10 bytes of buf16 into iData |
596 Mem::Copy(&iData[0x01],buf16.Ptr(),s*2);//Copy up to 10 bytes of buf16 into iData |
|
597 |
580 TInt offset=s; |
598 TInt offset=s; |
581 rem-=s; |
599 rem-=s; |
582 s=Min(rem,6); |
600 s=Min(rem,6); |
583 Mem::Copy(&iData[0x0E],buf16.Ptr()+offset,s*2); |
601 Mem::Copy(&iData[0x0E],buf16.Ptr()+offset,s*2); |
|
602 |
584 offset+=s; |
603 offset+=s; |
585 rem-=s; |
604 rem-=s; |
|
605 |
586 s=Min(rem,2); |
606 s=Min(rem,2); |
587 Mem::Copy(&iData[0x1C],buf16.Ptr()+offset,s*2); |
607 Mem::Copy(&iData[0x1C],buf16.Ptr()+offset,s*2); |
588 rem-=s; |
608 rem-=s; |
|
609 |
589 if (rem==0) |
610 if (rem==0) |
590 orderNo|=0x40; |
611 orderNo|=0x40; |
|
612 |
591 iData[0]=orderNo; |
613 iData[0]=orderNo; |
592 } |
614 } |
593 |
615 |
|
616 |
|
617 //----------------------------------------------------------------------------- |
|
618 /** |
|
619 Read KMaxVFatEntryName unicode chars from the entry |
|
620 */ |
594 void TFatDirEntry::ReadVFatEntry(TDes16& aBuf) const |
621 void TFatDirEntry::ReadVFatEntry(TDes16& aBuf) const |
595 // |
622 { |
596 // Read KMaxVFatEntryName unicode chars from the entry |
|
597 // |
|
598 { |
|
599 |
|
600 aBuf.SetLength(KMaxVFatEntryName); |
623 aBuf.SetLength(KMaxVFatEntryName); |
601 Mem::Copy(&aBuf[0],&iData[0x01],5*2); |
624 Mem::Copy(&aBuf[0],&iData[0x01],5*2); |
602 Mem::Copy(&aBuf[5],&iData[0x0E],6*2); |
625 Mem::Copy(&aBuf[5],&iData[0x0E],6*2); |
603 Mem::Copy(&aBuf[11],&iData[0x1C],2*2); |
626 Mem::Copy(&aBuf[11],&iData[0x1C],2*2); |
604 } |
627 } |
605 |
628 |
606 void CFatMountCB::WriteDirEntryL(TEntryPos& aPos,const TFatDirEntry& aFatDirEntry,const TDesC& aLongName) |
629 //----------------------------------------------------------------------------- |
607 // |
630 /** |
608 // Write a VFAT directory entry to disk at position aPos - leave aPos refering to the dos entry |
631 Write a VFAT directory entry set to disk at position aPos - leave aPos refering to the dos entry |
609 // Assumes sufficient space has been created for it by AddDirEntry. |
632 Assumes sufficient space has been created for it by AddDirEntry. |
610 // |
633 For Rugged FAT mode bulk writing of the whole entryset is OK. If the entryset fits into media atomic write unit, the |
611 { |
634 write is transactional anyway. if the entryset is split between media atomic write units, the part of it with the DOS |
612 |
635 entry is written last; if this write operation fails, the artifact would be just several orphaned VFAT entries; |
613 __PRINT(_L("VFAT::CFatMountCB::WriteDirEntryL")); |
636 |
|
637 @param aPos in: specifies the entryste start position. out: points to the last (DOS) entry in the created entryset |
|
638 @param aFatDirEntry aDosEntry DOS entry |
|
639 @param aLongName VFAT entry long name |
|
640 */ |
|
641 void CFatMountCB::WriteDirEntryL(TEntryPos& aPos, const TFatDirEntry& aDosEntry, const TDesC& aLongName) |
|
642 { |
|
643 __PRINT2(_L("CFatMountCB::WriteDirEntryL() cl:%d, pos:%d"), aPos.Cluster(), aPos.Pos()); |
614 __ASSERT_DEBUG(aLongName.Length(),Fault(EVFatNoLongName)); |
644 __ASSERT_DEBUG(aLongName.Length(),Fault(EVFatNoLongName)); |
615 TEntryPos startPos(aPos.iCluster,aPos.iPos); |
645 |
616 TUint8 localBuf[KDefaultSectorSize]; |
646 //-- scratch buffer for whole VFAT entryset. Max number of entries in it is 21 entry or 672 bytes. |
617 TUint8 cksum=CalculateShortNameCheckSum(aFatDirEntry.Name()); |
647 //-- in the worst case the entryset can span across 3 clusters (512 bytes per cluster) |
618 TInt numEntries=NumberOfVFatEntries(aLongName.Length())-1; // Excluding dos entry |
648 //-- Using the scratch buffer is not ideal, but write-back directory cache isn't in place yet |
619 // see if all entries written to one sector |
649 const TUint KBufSize = 680; |
620 // single sector writes not supported if sector size>default size |
650 TUint8 scratchBuf[KBufSize]; |
621 TInt dosOffset=numEntries<<KSizeOfFatDirEntryLog2; |
651 |
622 TInt absolutePos=(aPos.iCluster<<ClusterSizeLog2())+ClusterRelativePos(aPos.iPos); |
652 const TUint8 cksum=CalculateShortNameCheckSum(aDosEntry.Name()); |
623 TBool isSameSector=(((absolutePos^(absolutePos+dosOffset))>>SectorSizeLog2())==0 && ((TUint)(1<<SectorSizeLog2())<=KDefaultSectorSize)); |
653 TUint numEntries=NumberOfVFatEntries(aLongName.Length())-1; // Excluding dos entry |
624 TFatDirEntry vFatEntry; |
654 |
625 vFatEntry.InitializeAsVFat(cksum); |
655 ASSERT(KBufSize >= ((numEntries+1)<<KSizeOfFatDirEntryLog2)); |
626 TInt offset=0; |
656 TEntryPos startPos; |
|
657 |
|
658 for(;;) |
|
659 { |
|
660 TInt posInBuf = 0; |
|
661 startPos = aPos; |
|
662 TBool movedCluster = EFalse; |
|
663 |
|
664 TUint nRemLen = KMaxVFatEntryName*(numEntries-1); |
|
665 |
|
666 while(numEntries) |
|
667 { |
|
668 TFatDirEntry* pEntry = (TFatDirEntry*)(&scratchBuf[posInBuf]); |
|
669 |
|
670 pEntry->SetVFatEntry(aLongName, nRemLen, cksum); |
|
671 |
|
672 posInBuf += KSizeOfFatDirEntry; |
|
673 MoveToNextEntryL(aPos); |
|
674 |
|
675 numEntries--; |
|
676 movedCluster = (startPos.Cluster() != aPos.Cluster()); //-- if moved to another cluser, need to flush buffer |
|
677 |
|
678 if(!numEntries || movedCluster) |
|
679 break; //-- VFAT entryset is completed |
|
680 |
|
681 ASSERT(nRemLen >= (TUint)KMaxVFatEntryName); |
|
682 nRemLen -= KMaxVFatEntryName; |
|
683 } |
|
684 |
|
685 if(movedCluster) |
|
686 { |
|
687 DirWriteL(startPos, TPtrC8(&scratchBuf[0], posInBuf)); |
|
688 continue; |
|
689 } |
|
690 |
|
691 if(!numEntries) |
|
692 {//-- need to append DOS entry |
|
693 Mem::Copy(&scratchBuf[posInBuf], &aDosEntry, KSizeOfFatDirEntry); |
|
694 posInBuf+= KSizeOfFatDirEntry; |
|
695 DirWriteL(startPos, TPtrC8(&scratchBuf[0], posInBuf)); |
|
696 break; |
|
697 } |
|
698 |
|
699 }//for(;;) |
|
700 } |
|
701 |
|
702 |
|
703 |
|
704 //--------------------------------------------------------------------------------- |
|
705 |
|
706 void CFatMountCB::DoEraseEntrySetChunkL(const TEntrySetChunkInfo& aEntrySetChunk) |
|
707 { |
|
708 |
|
709 //-- scratch buffer for whole VFAT entryset. Max number of entries in it is 21 entry or 672 bytes. |
|
710 //-- in the worst case the entryset can span across 3 clusters (512 bytes per cluster) |
|
711 //-- Using the scratch buffer is not ideal, but write-back directory cache isn't in place yet |
|
712 |
|
713 const TUint KBufSize = 680; |
|
714 TBuf8<KBufSize> scratchBuf; |
|
715 |
|
716 TUint numEntries = aEntrySetChunk.iNumEntries; |
|
717 |
|
718 ASSERT(numEntries >0 && numEntries <= KMaxVFatEntries); |
|
719 const TUint32 KChunkLen = numEntries << KSizeOfFatDirEntryLog2; |
|
720 |
|
721 DirReadL(aEntrySetChunk.iEntryPos, KChunkLen, scratchBuf); |
|
722 |
|
723 TInt posInBuf = 0; |
627 while (numEntries--) |
724 while (numEntries--) |
628 { |
725 { |
629 vFatEntry.SetVFatEntry(aLongName,KMaxVFatEntryName*numEntries);// KMaxVFatEntryName=13 |
726 TFatDirEntry* pEntry = (TFatDirEntry*)(scratchBuf.Ptr()+posInBuf); |
630 if(isSameSector) |
727 pEntry->SetErased(); |
631 { |
728 posInBuf += KSizeOfFatDirEntry; |
632 Mem::Copy(&localBuf[offset],&vFatEntry,KSizeOfFatDirEntry); |
|
633 offset+=KSizeOfFatDirEntry; |
|
634 MoveToNextEntryL(aPos); |
|
635 } |
|
636 else |
|
637 { |
|
638 WriteDirEntryL(aPos,vFatEntry); |
|
639 MoveToNextEntryL(aPos); |
|
640 } |
|
641 } |
|
642 if(isSameSector) |
|
643 { |
|
644 Mem::Copy(&localBuf[offset],&aFatDirEntry,KSizeOfFatDirEntry); |
|
645 |
|
646 //-- use special interface to access FAT directory file |
|
647 DirWriteL(startPos,TPtrC8(&localBuf[0],dosOffset+KSizeOfFatDirEntry)); |
|
648 } |
729 } |
|
730 |
|
731 DirWriteL(aEntrySetChunk.iEntryPos, scratchBuf); |
|
732 } |
|
733 |
|
734 //--------------------------------------------------------------------------------- |
|
735 /** |
|
736 Erase whole VFAT entryset. |
|
737 For Rugged FAT the situation is more complicated: we need firstly delete the DOS entry _atomically_ i.e. if this operation fails, |
|
738 the whole VFAT entryset won't be broken. Deleting VFAT entries doesn't require the atomic media writes; DOS entry contains necessary |
|
739 information about data stream. |
|
740 |
|
741 @param aPos position of the entryset start in the directory. |
|
742 @param aFirstEntry first entry in the entryset, it can be DOS entry |
|
743 |
|
744 */ |
|
745 void CFatMountCB::EraseDirEntryL(TEntryPos aPos,const TFatDirEntry& aFirstEntry) |
|
746 { |
|
747 __PRINT2(_L("CFatMountCB::EraseDirEntryL() cl:%d, offset:%d"), aPos.Cluster(), aPos.Pos()); |
|
748 |
|
749 TUint numEntries=0; |
|
750 if (aFirstEntry.IsVFatEntry()) |
|
751 { |
|
752 numEntries=aFirstEntry.NumFollowing(); |
|
753 numEntries++; //-- take into account the last DOS entry |
|
754 } |
|
755 else |
|
756 {//-- we are deleting a single DOS entry. This is an atomic operation. |
|
757 EraseDirEntryL(aPos); |
|
758 return; |
|
759 } |
|
760 |
|
761 ASSERT(numEntries > 1 && numEntries <= KMaxVFatEntries); |
|
762 |
|
763 TEntrySetChunkInfo chunksInfo[TEntrySetChunkInfo::KMaxChunks]; |
|
764 |
|
765 //-- 1. check if the entryset fits into a unit of write ganularity. This will be 1 sector for rugged FAT or 1 cluster otherwise |
|
766 |
|
767 TUint32 MaxWriteGranularityLog2; |
|
768 |
|
769 if(IsRuggedFSys()) |
|
770 { |
|
771 MaxWriteGranularityLog2 = AtomicWriteGranularityLog2(); |
|
772 } |
|
773 else if(IsRootDir(aPos)) |
|
774 {//-- root dir. for FAT12/16 is a special case, it is not made of clusters. it's unit is 1 sector. |
|
775 MaxWriteGranularityLog2 = KDefSectorSzLog2; |
|
776 } |
|
777 else |
|
778 {//-- minimal unit size will be a cluster |
|
779 MaxWriteGranularityLog2 = ClusterSizeLog2(); |
|
780 } |
|
781 |
|
782 |
|
783 { |
|
784 const TUint64 KEntrySetStartPos = MakeLinAddrL(aPos); |
|
785 const TUint64 KEntrySetLogicalEndPos = KEntrySetStartPos + (numEntries << KSizeOfFatDirEntryLog2); |
|
786 |
|
787 const TUint64 KBlockEndPos = ((KEntrySetLogicalEndPos-1) >> MaxWriteGranularityLog2) << MaxWriteGranularityLog2; |
|
788 const TUint64 KBlockStartPos = (KEntrySetStartPos >> MaxWriteGranularityLog2) << MaxWriteGranularityLog2; |
|
789 |
|
790 if(KBlockEndPos == KBlockStartPos) |
|
791 {//-- whole entryet is in the same block; the whole entryset erase operation will be atomic for Rugged/non-rugged FAT |
|
792 chunksInfo[0].iEntryPos = aPos; |
|
793 chunksInfo[0].iNumEntries = numEntries; |
|
794 DoEraseEntrySetChunkL(chunksInfo[0]); |
|
795 return; |
|
796 } |
|
797 |
|
798 } |
|
799 |
|
800 //-- the entryset is split on max. 3 parts between units of write granularity (see MaxWriteGranularityLog2). |
|
801 ASSERT(numEntries > 1 && numEntries <= KMaxVFatEntries); |
|
802 |
|
803 TInt cntChunk = 1; //-- there is at least 1 entries chunk |
|
804 TEntrySetChunkInfo* pChunkInfo = chunksInfo; |
|
805 |
|
806 //-- collect information about dir. entry chunks that reside in different units of write granularity |
|
807 for(;;) |
|
808 { |
|
809 TBool movedUnit = EFalse; |
|
810 |
|
811 pChunkInfo->iEntryPos = aPos; |
|
812 pChunkInfo->iNumEntries = 0; |
|
813 |
|
814 const TUint64 KChunkStartPos = MakeLinAddrL(aPos); |
|
815 const TUint64 KChunkBlockStartPos = (KChunkStartPos >> MaxWriteGranularityLog2) << MaxWriteGranularityLog2; |
|
816 const TUint64 KChunkBlockEndPos = (KChunkBlockStartPos-1) + (1<<MaxWriteGranularityLog2); |
|
817 |
|
818 while(numEntries) |
|
819 { |
|
820 pChunkInfo->iNumEntries++; |
|
821 MoveToNextEntryL(aPos); |
|
822 |
|
823 numEntries--; |
|
824 const TUint64 currPos = MakeLinAddrL(aPos); |
|
825 movedUnit = !(currPos >= KChunkBlockStartPos && currPos <= KChunkBlockEndPos); |
|
826 |
|
827 if(!numEntries || movedUnit) |
|
828 { |
|
829 break; |
|
830 } |
|
831 |
|
832 } |
|
833 |
|
834 if(movedUnit && numEntries) |
|
835 {//-- move to the next unit of write granularity |
|
836 ++pChunkInfo; |
|
837 ++cntChunk; |
|
838 ASSERT(cntChunk <= TEntrySetChunkInfo::KMaxChunks); |
|
839 continue; |
|
840 } |
|
841 |
|
842 |
|
843 ASSERT(!numEntries); |
|
844 break; |
|
845 } |
|
846 |
|
847 //-- now do bulk deletion, write data based on collected entries chunks. |
|
848 ASSERT(cntChunk > 0); |
|
849 |
|
850 //-- if it is a rugged FAT, we need to delete DOS entry first; it will be in the last chunk. |
|
851 if(IsRuggedFSys()) |
|
852 { |
|
853 const TInt dosEntryChunk = cntChunk-1; |
|
854 DoEraseEntrySetChunkL(chunksInfo[dosEntryChunk]); |
|
855 cntChunk--; |
|
856 } |
|
857 |
|
858 //-- it is also possible to joint entryset chunks together here if they belong to the same cluster. |
|
859 //-- the atomic write here is not required. |
|
860 |
|
861 //-- erase the rest of entries in reamining chunks. |
|
862 for(TInt i=0; i<cntChunk; ++i) |
|
863 { |
|
864 DoEraseEntrySetChunkL(chunksInfo[i]); |
|
865 } |
|
866 |
|
867 } |
|
868 |
|
869 //--------------------------------------------------------------------------------- |
|
870 /** |
|
871 Convert the volume label using the algorithm specified in the current locale-DLL. |
|
872 */ |
|
873 void LocaleUtils::ConvertFromUnicodeL(TDes8& aForeign, const TDesC16& aUnicode, TFatUtilityFunctions::TOverflowAction aOverflowAction) |
|
874 { |
|
875 if(aOverflowAction == TFatUtilityFunctions::EOverflowActionLeave) |
|
876 { |
|
877 GetCodePage().ConvertFromUnicodeL(aForeign, aUnicode, TCodePageUtils::EOverflowActionLeave); |
|
878 } |
649 else |
879 else |
650 WriteDirEntryL(aPos,aFatDirEntry); |
880 { |
651 } |
881 GetCodePage().ConvertFromUnicodeL(aForeign, aUnicode, TCodePageUtils::EOverflowActionTruncate); |
652 |
882 } |
653 void CFatMountCB::EraseDirEntryL(TEntryPos aPos,const TFatDirEntry& aFirstEntry) |
883 } |
654 // |
884 //--------------------------------------------------------------------------------- |
655 // Mark all entries in a VFat directory entry as erased |
885 /** |
656 // |
886 Convert the volume label using the algorithm specified in the current locale-DLL. |
657 { |
887 */ |
658 __PRINT(_L("VFAT::CFatMountCB::EraseDirEntryL")); |
888 void LocaleUtils::ConvertToUnicodeL(TDes16& aUnicode, const TDesC8& aForeign, TFatUtilityFunctions::TOverflowAction aOverflowAction) |
659 TInt numEntries=0; |
|
660 if (aFirstEntry.IsVFatEntry()) |
|
661 numEntries=aFirstEntry.NumFollowing(); |
|
662 if(IsRuggedFSys()&&numEntries) |
|
663 { |
|
664 TInt count=numEntries; |
|
665 TEntryPos pos=aPos; |
|
666 while(count--) |
|
667 MoveToNextEntryL(pos); |
|
668 EraseDirEntryL(pos); |
|
669 numEntries--; |
|
670 } |
|
671 FOREVER |
|
672 { |
|
673 EraseDirEntryL(aPos); |
|
674 if (!numEntries--) |
|
675 break; |
|
676 MoveToNextEntryL(aPos); |
|
677 } |
|
678 } |
|
679 |
|
680 |
|
681 void LocaleUtils::ConvertFromUnicodeL(TDes8& aForeign, const TDesC16& aUnicode, TFatUtilityFunctions::TOverflowAction aOverflowAction) |
|
682 // |
|
683 // Convert the volume label using the algorithm specified in the current locale-DLL. |
|
684 // |
|
685 { |
889 { |
686 if(aOverflowAction == TFatUtilityFunctions::EOverflowActionLeave) |
890 if(aOverflowAction == TFatUtilityFunctions::EOverflowActionLeave) |
687 { |
891 { |
688 GetCodePage().ConvertFromUnicodeL(aForeign, aUnicode, TCodePageUtils::EOverflowActionLeave); |
892 GetCodePage().ConvertToUnicodeL(aUnicode, aForeign, TCodePageUtils::EOverflowActionLeave); |
689 } |
893 } |
690 else |
894 else |
691 { |
895 { |
692 GetCodePage().ConvertFromUnicodeL(aForeign, aUnicode, TCodePageUtils::EOverflowActionTruncate); |
|
693 } |
|
694 } |
|
695 |
|
696 void LocaleUtils::ConvertToUnicodeL(TDes16& aUnicode, const TDesC8& aForeign, TFatUtilityFunctions::TOverflowAction aOverflowAction) |
|
697 // |
|
698 // Convert the volume label using the algorithm specified in the current locale-DLL. |
|
699 // |
|
700 { |
|
701 if(aOverflowAction == TFatUtilityFunctions::EOverflowActionLeave) |
|
702 { |
|
703 GetCodePage().ConvertToUnicodeL(aUnicode, aForeign, TCodePageUtils::EOverflowActionLeave); |
|
704 } |
|
705 else |
|
706 { |
|
707 GetCodePage().ConvertToUnicodeL(aUnicode, aForeign, TCodePageUtils::EOverflowActionTruncate); |
896 GetCodePage().ConvertToUnicodeL(aUnicode, aForeign, TCodePageUtils::EOverflowActionTruncate); |
708 } |
897 } |
709 } |
898 } |
710 |
899 |
|
900 //--------------------------------------------------------------------------------- |
|
901 /** |
|
902 Convert the volume label using the algorithm specified in the current locale-DLL. |
|
903 */ |
711 TBool LocaleUtils::IsLegalShortNameCharacter(TUint aCharacter,TBool aUseExtendedChars) |
904 TBool LocaleUtils::IsLegalShortNameCharacter(TUint aCharacter,TBool aUseExtendedChars) |
712 // |
|
713 // Convert the volume label using the algorithm specified in the current locale-DLL. |
|
714 // |
|
715 { |
905 { |
716 return GetCodePage().IsLegalShortNameCharacter(aCharacter, aUseExtendedChars); |
906 return GetCodePage().IsLegalShortNameCharacter(aCharacter, aUseExtendedChars); |
717 } |
907 } |
|
908 |
|
909 |
|
910 |
|
911 |
|
912 |
|
913 |
|
914 |
|
915 |
|
916 |