diff --git a/rtl/objpas/unicodedata.pas b/rtl/objpas/unicodedata.pas index 2403a9b658..b00ee4877c 100644 --- a/rtl/objpas/unicodedata.pas +++ b/rtl/objpas/unicodedata.pas @@ -274,6 +274,7 @@ type Props : PUCA_PropItemRec; VariableLowLimit : Word; VariableHighLimit : Word; + Dynamic : Boolean; public function IsVariable(const AWeight : PUCA_PropWeights) : Boolean; inline; end; @@ -320,8 +321,13 @@ type function CompareSortKey(const A, B : TUCASortKey) : Integer;overload; function CompareSortKey(const A : TUCASortKey; const B : array of Word) : Integer;overload; - function RegisterCollation(const ACollation : PUCA_DataBook) : Boolean; + function RegisterCollation(const ACollation : PUCA_DataBook) : Boolean;overload; + function RegisterCollation( + const ADirectory, + ALanguage : string + ) : Boolean;overload; function UnregisterCollation(const AName : ansistring): Boolean; + procedure UnregisterCollations(const AFreeDynamicCollations : Boolean); function FindCollation(const AName : ansistring): PUCA_DataBook;overload; function FindCollation(const AIndex : Integer): PUCA_DataBook;overload; function GetCollationCount() : Integer; @@ -330,6 +336,29 @@ type const ABaseName : ansistring; const AChangedFields : TCollationFields ); + function LoadCollation( + const AData : Pointer; + const ADataLength : Integer + ) : PUCA_DataBook;overload; + function LoadCollation(const AFileName : string) : PUCA_DataBook;overload; + function LoadCollation( + const ADirectory, + ALanguage : string + ) : PUCA_DataBook;overload; + procedure FreeCollation(AItem : PUCA_DataBook); + +type + TEndianKind = (Little, Big); +const + ENDIAN_SUFFIX : array[TEndianKind] of string[2] = ('le','be'); +{$IFDEF ENDIAN_LITTLE} + ENDIAN_NATIVE = TEndianKind.Little; + ENDIAN_NON_NATIVE = TEndianKind.Big; +{$ENDIF ENDIAN_LITTLE} +{$IFDEF ENDIAN_BIG} + ENDIAN_NATIVE = TEndianKind.Big; + ENDIAN_NON_NATIVE = TEndianKind.Little; +{$ENDIF ENDIAN_BIG} resourcestring SCollationNotFound = 'Collation not found : "%s".'; @@ -535,6 +564,21 @@ begin Result := a <= Cardinal(b); end; +type + TBitOrder = 0..7; +function IsBitON(const AData : Byte; const ABit : TBitOrder) : Boolean ;inline; +begin + Result := ( ( AData and ( 1 shl ABit ) ) <> 0 ); +end; + +procedure SetBit(var AData : Byte; const ABit : TBitOrder; const AValue : Boolean);inline; +begin + if AValue then + AData := AData or (1 shl (ABit mod 8)) + else + AData := AData and ( not ( 1 shl ( ABit mod 8 ) ) ); +end; + var CollationTable : array of PUCA_DataBook; function IndexOfCollation(const AName : string) : Integer; @@ -565,6 +609,23 @@ begin end; end; +function RegisterCollation(const ADirectory, ALanguage : string) : Boolean; +var + cl : PUCA_DataBook; +begin + cl := LoadCollation(ADirectory,ALanguage); + if (cl = nil) then + exit(False); + try + Result := RegisterCollation(cl); + except + FreeCollation(cl); + raise; + end; + if not Result then + FreeCollation(cl); +end; + function UnregisterCollation(const AName : ansistring): Boolean; var i, c : Integer; @@ -582,6 +643,21 @@ begin end; end; +procedure UnregisterCollations(const AFreeDynamicCollations : Boolean); +var + i : Integer; + cl : PUCA_DataBook; +begin + for i := Low(CollationTable) to High(CollationTable) do begin + if CollationTable[i].Dynamic then begin + cl := CollationTable[i]; + CollationTable[i] := nil; + FreeCollation(cl); + end; + end; + SetLength(CollationTable,0); +end; + function FindCollation(const AName : ansistring): PUCA_DataBook;overload; var i : Integer; @@ -632,6 +708,190 @@ begin p^.VariableLowLimit := base^.VariableHighLimit; end; +type + TSerializedCollationHeader = packed record + Base : TCollationName; + Version : TCollationName; + CollationName : TCollationName; + VariableWeight : Byte; + Backwards : Byte; + BMP_Table1Length : DWord; + BMP_Table2Length : DWord; + OBMP_Table1Length : DWord; + OBMP_Table2Length : DWord; + PropCount : DWord; + VariableLowLimit : Word; + VariableHighLimit : Word; + ChangedFields : Byte; + end; + PSerializedCollationHeader = ^TSerializedCollationHeader; + +procedure FreeCollation(AItem : PUCA_DataBook); +var + h : PSerializedCollationHeader; +begin + if (AItem = nil) or not(AItem^.Dynamic) then + exit; + h := PSerializedCollationHeader(PtrUInt(AItem) + SizeOf(TUCA_DataBook)); + if (AItem^.BMP_Table1 <> nil) then + FreeMem(AItem^.BMP_Table1,h^.BMP_Table1Length); + if (AItem^.BMP_Table2 <> nil) then + FreeMem(AItem^.BMP_Table2,h^.BMP_Table2Length); + if (AItem^.OBMP_Table1 <> nil) then + FreeMem(AItem^.OBMP_Table1,h^.OBMP_Table1Length); + if (AItem^.OBMP_Table2 <> nil) then + FreeMem(AItem^.OBMP_Table2,h^.OBMP_Table2Length); + if (AItem^.Props <> nil) then + FreeMem(AItem^.Props,h^.PropCount); + FreeMem(AItem,(SizeOf(TUCA_DataBook)+SizeOf(TSerializedCollationHeader))); +end; + +function LoadCollation( + const AData : Pointer; + const ADataLength : Integer +) : PUCA_DataBook; +var + dataPointer : PByte; + readedLength : LongInt; + + function ReadBuffer(ADest : Pointer; ALength : LongInt) : Boolean; + begin + Result := (readedLength + ALength) <= ADataLength; + if not result then + exit; + Move(dataPointer^,ADest^,ALength); + Inc(dataPointer,ALength); + readedLength := readedLength + ALength; + end; + +var + r : PUCA_DataBook; + h : PSerializedCollationHeader; + cfs : TCollationFields; + i : Integer; + baseName : TCollationName; +begin + readedLength := 0; + dataPointer := AData; + r := AllocMem((SizeOf(TUCA_DataBook)+SizeOf(TSerializedCollationHeader))); + try + h := PSerializedCollationHeader(PtrUInt(r) + SizeOf(TUCA_DataBook)); + if not ReadBuffer(h,SizeOf(TSerializedCollationHeader)) then + exit; + r^.Version := h^.Version; + r^.CollationName := h^.CollationName; + r^.VariableWeight := TUCA_VariableKind(h^.VariableWeight); + r^.Backwards[0] := IsBitON(h^.Backwards,0); + r^.Backwards[1] := IsBitON(h^.Backwards,1); + r^.Backwards[2] := IsBitON(h^.Backwards,2); + r^.Backwards[3] := IsBitON(h^.Backwards,3); + if (h^.BMP_Table1Length > 0) then begin + r^.BMP_Table1 := GetMem(h^.BMP_Table1Length); + if not ReadBuffer(r^.BMP_Table1,h^.BMP_Table1Length) then + exit; + end; + if (h^.BMP_Table2Length > 0) then begin + r^.BMP_Table2 := GetMem(h^.BMP_Table2Length); + if not ReadBuffer(r^.BMP_Table2,h^.BMP_Table2Length) then + exit; + end; + if (h^.OBMP_Table1Length > 0) then begin + r^.OBMP_Table1 := GetMem(h^.OBMP_Table1Length); + if not ReadBuffer(r^.OBMP_Table1,h^.OBMP_Table1Length) then + exit; + end; + if (h^.OBMP_Table2Length > 0) then begin + r^.OBMP_Table2 := GetMem(h^.OBMP_Table2Length); + if not ReadBuffer(r^.OBMP_Table2,h^.OBMP_Table2Length) then + exit; + end; + r^.PropCount := h^.PropCount; + if (h^.PropCount > 0) then begin + r^.Props := GetMem(h^.PropCount); + if not ReadBuffer(r^.Props,h^.PropCount) then + exit; + end; + r^.VariableLowLimit := h^.VariableLowLimit; + r^.VariableHighLimit := h^.VariableHighLimit; + + cfs := []; + for i := Ord(Low(TCollationField)) to Ord(High(TCollationField)) do begin + if IsBitON(h^.ChangedFields,i) then + cfs := cfs + [TCollationField(i)]; + end; + if (h^.Base <> '') then + baseName := h^.Base + else if (h^.CollationName <> ROOT_COLLATION_NAME) then + baseName := ROOT_COLLATION_NAME + else + baseName := ''; + if (baseName <> '') then + PrepareCollation(r,baseName,cfs); + r^.Dynamic := True; + Result := r; + except + FreeCollation(r); + raise; + end; +end; + +{$PUSH} +function LoadCollation(const AFileName : string) : PUCA_DataBook; +const + BLOCK_SIZE = 16*1024; +var + f : File of Byte; + locSize, locReaded, c : LongInt; + locBuffer : PByte; + locBlockSize : LongInt; +begin + Result := nil; +{$I-} + if (AFileName = '') then + exit; + Assign(f,AFileName); + Reset(f); + try + if (IOResult <> 0) then + exit; + locSize := FileSize(f); + if (locSize < SizeOf(TSerializedCollationHeader)) then + exit; + locBuffer := GetMem(locSize); + try + locBlockSize := BLOCK_SIZE; + locReaded := 0; + while (locReaded < locSize) do begin + if (locBlockSize > (locSize-locReaded)) then + locBlockSize := locSize-locReaded; + BlockRead(f,locBuffer[locReaded],locBlockSize,c); + if (IOResult <> 0) or (c <= 0) then + exit; + locReaded := locReaded + c; + end; + Result := LoadCollation(locBuffer,locSize); + finally + FreeMem(locBuffer,locSize); + end; + finally + Close(f); + end; +end; +{$POP} + +function LoadCollation(const ADirectory, ALanguage : string) : PUCA_DataBook; +var + fileName : string; +begin + fileName := ADirectory; + if (fileName <> '') then begin + if (fileName[Length(fileName)] <> DirectorySeparator) then + fileName := fileName + DirectorySeparator; + end; + fileName := fileName + 'collation_' + ALanguage + '_' + ENDIAN_SUFFIX[ENDIAN_NATIVE] + '.bco'; + Result := LoadCollation(fileName); +end; + {$INCLUDE unicodedata.inc} {$IFDEF ENDIAN_LITTLE} {$INCLUDE unicodedata_le.inc} @@ -1026,21 +1286,6 @@ begin end; end; -type - TBitOrder = 0..7; -function IsBitON(const AData : Byte; const ABit : TBitOrder) : Boolean ;inline; -begin - Result := ( ( AData and ( 1 shl ABit ) ) <> 0 ); -end; - -procedure SetBit(var AData : Byte; const ABit : TBitOrder; const AValue : Boolean);inline; -begin - if AValue then - AData := AData or (1 shl (ABit mod 8)) - else - AData := AData and ( not ( 1 shl ( ABit mod 8 ) ) ); -end; - { TUCA_PropItemContextTreeNodeRec } function TUCA_PropItemContextTreeNodeRec.GetLeftNode: PUCA_PropItemContextTreeNodeRec; diff --git a/utils/unicode/cldrhelper.pas b/utils/unicode/cldrhelper.pas index e5324f6609..a1495244f5 100644 --- a/utils/unicode/cldrhelper.pas +++ b/utils/unicode/cldrhelper.pas @@ -208,14 +208,16 @@ type ) : Integer; function FindCollationDefaultItemName(ACollation : TCldrCollation) : string; procedure GenerateCdlrCollation( - ACollation : TCldrCollation; - AItemName : string; - AStoreName : string; + ACollation : TCldrCollation; + AItemName : string; + AStoreName : string; AStream, ANativeEndianStream, - AOtherEndianStream : TStream; - ARootChars : TOrderedCharacters; - ARootWeigths : TUCA_LineRecArray + AOtherEndianStream, + ABinaryNativeEndianStream, + ABinaryOtherEndianStream : TStream; + ARootChars : TOrderedCharacters; + ARootWeigths : TUCA_LineRecArray ); procedure GenerateUCA_CLDR_Head( @@ -1635,14 +1637,16 @@ begin end; procedure GenerateCdlrCollation( - ACollation : TCldrCollation; - AItemName : string; - AStoreName : string; + ACollation : TCldrCollation; + AItemName : string; + AStoreName : string; AStream, ANativeEndianStream, - AOtherEndianStream : TStream; - ARootChars : TOrderedCharacters; - ARootWeigths : TUCA_LineRecArray + AOtherEndianStream, + ABinaryNativeEndianStream, + ABinaryOtherEndianStream : TStream; + ARootChars : TOrderedCharacters; + ARootWeigths : TUCA_LineRecArray ); procedure AddLine(const ALine : ansistring; ADestStream : TStream); @@ -1665,6 +1669,8 @@ var ucaoSecondTable : TucaOBmpSecondTable; locHasProps : Boolean; s : string; + serializedHeader : TSerializedCollationHeader; + e : TCollationField; begin locItem := ACollation.Find(AItemName); if (locItem = nil) then @@ -1707,6 +1713,43 @@ begin AddLine('{$endif FPC_LITTLE_ENDIAN}',AStream); end; GenerateUCA_CLDR_Registration(AStream,@locUcaBook); + + FillChar(serializedHeader,SizeOf(TSerializedCollationHeader),0); + serializedHeader.Base := locItem.Base; + serializedHeader.Version := ACollation.Version; + serializedHeader.CollationName := ACollation.Language; + serializedHeader.VariableWeight := Ord(locUcaBook.VariableWeight); + SetBit(serializedHeader.Backwards,0,locUcaBook.Backwards[0]); + SetBit(serializedHeader.Backwards,1,locUcaBook.Backwards[1]); + SetBit(serializedHeader.Backwards,2,locUcaBook.Backwards[2]); + SetBit(serializedHeader.Backwards,3,locUcaBook.Backwards[3]); + if locHasProps then begin + serializedHeader.BMP_Table1Length := Length(ucaFirstTable); + serializedHeader.BMP_Table2Length := Length(TucaBmpSecondTableItem) * + (Length(ucaSecondTable) * SizeOf(UInt24)); + serializedHeader.OBMP_Table1Length := Length(ucaoFirstTable) * SizeOf(Word); + serializedHeader.OBMP_Table2Length := Length(TucaOBmpSecondTableItem) * + (Length(ucaoSecondTable) * SizeOf(UInt24)); + serializedHeader.PropCount := locUcaProps^.ItemSize; + serializedHeader.VariableLowLimit := locUcaProps^.VariableLowLimit; + serializedHeader.VariableHighLimit := locUcaProps^.VariableHighLimit; + end else begin + serializedHeader.VariableLowLimit := High(Word); + serializedHeader.VariableHighLimit := 0; + end; + serializedHeader.ChangedFields := 0; + for e := Low(TCollationField) to High(TCollationField) do begin + if (e in locItem.ChangedFields) then + SetBit(serializedHeader.ChangedFields,Ord(e),True); + end; + ABinaryNativeEndianStream.Write(serializedHeader,SizeOf(serializedHeader)); + ReverseRecordBytes(serializedHeader); + ABinaryOtherEndianStream.Write(serializedHeader,SizeOf(serializedHeader)); + if locHasProps then begin + GenerateBinaryUCA_BmpTables(ABinaryNativeEndianStream,ABinaryOtherEndianStream,ucaFirstTable,ucaSecondTable); + GenerateBinaryUCA_OBmpTables(ABinaryNativeEndianStream,ABinaryOtherEndianStream,ucaoFirstTable,ucaoSecondTable); + GenerateBinaryUCA_PropTable(ABinaryNativeEndianStream,ABinaryOtherEndianStream,locUcaProps); + end; finally locSequence.Clear(); FreeUcaBook(locUcaProps); diff --git a/utils/unicode/cldrparser.lpr b/utils/unicode/cldrparser.lpr index 9fa60926f2..a8d98796c1 100644 --- a/utils/unicode/cldrparser.lpr +++ b/utils/unicode/cldrparser.lpr @@ -22,9 +22,10 @@ program cldrparser; {$mode objfpc}{$H+} +{ $define WINCE_TEST} uses - SysUtils, classes, getopts, + SysUtils, classes, getopts,{$ifdef WINCE}StreamIO,{$endif} cldrhelper, helper, cldrtest, cldrxml, unicodeset; const @@ -66,6 +67,12 @@ var idx, k : Integer; s : string; begin +{$ifdef WINCE_TEST} + ADataDir := ExtractFilePath(ParamStr(0))+'data'; + AOuputDir := ADataDir; + ACollationFileName := 'sv.xml'; + exit(True); +{$endif WINCE_TEST} if (ParamCount() = 0) then exit(False); Result := True; @@ -101,14 +108,41 @@ end; var orderedChars : TOrderedCharacters; ucaBook : TUCA_DataBook; - stream, streamNE, streamOE : TMemoryStream; + stream, streamNE, streamOE, binaryStreamNE, binaryStreamOE : TMemoryStream; s, collationFileName, collationTypeName : string; i , c: Integer; collation : TCldrCollation; dataPath, outputPath : string; collationItem : TCldrCollationItem; testSuiteFlag : Boolean; +{$ifdef WINCE} + fs : TFileStream; +{$endif WINCE} begin +{$ifdef WINCE} + s := ExtractFilePath(ParamStr(0))+'cldr-log.txt'; + DeleteFile(s); + fs := TFileStream.Create(s,fmCreate); + AssignStream(Output,fs); + Rewrite(Output); + s := ExtractFilePath(ParamStr(0))+'cldr-err.txt'; + DeleteFile(s); + fs := TFileStream.Create(s,fmCreate); + AssignStream(ErrOutput,fs); + Rewrite(ErrOutput); +{$endif WINCE} +{$ifdef WINCE_TEST} + testSuiteFlag := True; + try + exec_tests(); + except + on e : Exception do begin + WriteLn('Exception : '+e.Message); + raise; + end; + end; + exit; +{$endif WINCE_TEST} dataPath := ''; outputPath := ''; collationFileName := ''; @@ -132,10 +166,12 @@ begin outputPath := dataPath else outputPath := IncludeTrailingPathDelimiter(outputPath); +{$ifndef WINCE_TEST} if (ParamCount() = 0) then begin WriteLn(SUsageText); Halt(1); end; +{$endif WINCE_TEST} if not( FileExists(dataPath+'UCA_Rules_SHORT.xml') and FileExists(dataPath+'allkeys.txt') @@ -155,6 +191,8 @@ begin stream := nil; streamNE := nil; streamOE := nil; + binaryStreamNE := nil; + binaryStreamOE := nil; collation := TCldrCollation.Create(); try ParseCollationDocument(collationFileName,collation,TCldrParserMode.HeaderParsing); @@ -194,9 +232,12 @@ begin stream.Clear(); streamNE := TMemoryStream.Create(); streamOE := TMemoryStream.Create(); + binaryStreamNE := TMemoryStream.Create(); + binaryStreamOE := TMemoryStream.Create(); s := COLLATION_FILE_PREFIX + ChangeFileExt(LowerCase(ExtractFileName(collationFileName)),'.pas'); GenerateCdlrCollation( collation,collationTypeName,s,stream,streamNE,streamOE, + binaryStreamNE,binaryStreamOE, orderedChars,ucaBook.Lines ); stream.SaveToFile(ExtractFilePath(collationFileName)+s); @@ -204,8 +245,20 @@ begin streamNE.SaveToFile(ExtractFilePath(collationFileName)+GenerateEndianIncludeFileName(s,ENDIAN_NATIVE)); streamOE.SaveToFile(ExtractFilePath(collationFileName)+GenerateEndianIncludeFileName(s,ENDIAN_NON_NATIVE)); end; + if (binaryStreamNE.Size > 0) then begin + binaryStreamNE.SaveToFile( + ExtractFilePath(collationFileName) + + ChangeFileExt(s,Format('_%s.bco',[ENDIAN_SUFFIX[ENDIAN_NATIVE]])) + ); + binaryStreamOE.SaveToFile( + ExtractFilePath(collationFileName) + + ChangeFileExt(s,Format('_%s.bco',[ENDIAN_SUFFIX[ENDIAN_NON_NATIVE]])) + ); + end; end; finally + binaryStreamOE.Free(); + binaryStreamNE.Free(); streamOE.Free(); streamNE.Free(); stream.Free(); diff --git a/utils/unicode/helper.pas b/utils/unicode/helper.pas index e171a72672..1e10910f5d 100644 --- a/utils/unicode/helper.pas +++ b/utils/unicode/helper.pas @@ -487,11 +487,23 @@ const var AFirstTable : TucaBmpFirstTable; var ASecondTable : TucaBmpSecondTable ); + procedure GenerateBinaryUCA_BmpTables( + ANativeEndianStream, + ANonNativeEndianStream : TStream; + var AFirstTable : TucaBmpFirstTable; + var ASecondTable : TucaBmpSecondTable + ); procedure GenerateUCA_PropTable( ADest : TStream; const APropBook : PUCA_PropBook; const AEndian : TEndianKind ); + procedure GenerateBinaryUCA_PropTable( + // WARNING : files must be generated for each endianess (Little / Big) + ANativeEndianStream, + ANonNativeEndianStream : TStream; + const APropBook : PUCA_PropBook + ); procedure GenerateUCA_OBmpTables( AStream, ANativeEndianStream, @@ -499,6 +511,12 @@ const var AFirstTable : TucaOBmpFirstTable; var ASecondTable : TucaOBmpSecondTable ); + procedure GenerateBinaryUCA_OBmpTables( + ANativeEndianStream, + ANonNativeEndianStream : TStream; + var AFirstTable : TucaOBmpFirstTable; + var ASecondTable : TucaOBmpSecondTable + ); procedure Parse_UnicodeData( ADataAStream : TMemoryStream; @@ -611,7 +629,6 @@ const ): PPropRec; inline;overload; procedure FromUCS4(const AValue : TUnicodeCodePoint; var AHighS, ALowS : Word);inline; function ToUCS4(const AHighS, ALowS : Word) : TUnicodeCodePoint; inline; -//-------------------- type TBitOrder = 0..7; @@ -640,6 +657,29 @@ type const ADataLen : Integer ); +type + TCollationName = string[128]; + TSerializedCollationHeader = packed record + Base : TCollationName; + Version : TCollationName; + CollationName : TCollationName; + VariableWeight : Byte; + Backwards : Byte; + BMP_Table1Length : DWord; + BMP_Table2Length : DWord; + OBMP_Table1Length : DWord; + OBMP_Table2Length : DWord; + PropCount : DWord; + VariableLowLimit : Word; + VariableHighLimit : Word; + ChangedFields : Byte; + end; + PSerializedCollationHeader = ^TSerializedCollationHeader; + + procedure ReverseRecordBytes(var AItem : TSerializedCollationHeader); + procedure ReverseBytes(var AData; const ALength : Integer); + procedure ReverseArray(var AValue; const AArrayLength, AItemSize : PtrInt); + resourcestring SInsufficientMemoryBuffer = 'Insufficient Memory Buffer'; @@ -3294,6 +3334,28 @@ begin AddLine(ANonNativeEndianStream,' );' + sLineBreak); end; +procedure GenerateBinaryUCA_BmpTables( + ANativeEndianStream, + ANonNativeEndianStream : TStream; + var AFirstTable : TucaBmpFirstTable; + var ASecondTable : TucaBmpSecondTable +); +var + i, j : Integer; + value : UInt24; +begin + ANativeEndianStream.Write(AFirstTable[0],Length(AFirstTable)); + ANonNativeEndianStream.Write(AFirstTable[0],Length(AFirstTable)); + for i := Low(ASecondTable) to High(ASecondTable) do begin + for j := Low(TucaBmpSecondTableItem) to High(TucaBmpSecondTableItem) do begin + value := ASecondTable[i][j]; + ANativeEndianStream.Write(value,SizeOf(value)); + ReverseBytes(value,SizeOf(value)); + ANonNativeEndianStream.Write(value,SizeOf(value)); + end; + end; +end; + procedure GenerateUCA_PropTable( // WARNING : files must be generated for each endianess (Little / Big) ADest : TStream; @@ -3336,6 +3398,17 @@ begin AddLine(' );' + sLineBreak); end; +procedure GenerateBinaryUCA_PropTable( +// WARNING : files must be generated for each endianess (Little / Big) + ANativeEndianStream, + ANonNativeEndianStream : TStream; + const APropBook : PUCA_PropBook +); +begin + ANativeEndianStream.Write(APropBook^.Items^,APropBook^.ItemSize); + ANonNativeEndianStream.Write(APropBook^.ItemsOtherEndian^,APropBook^.ItemSize); +end; + procedure GenerateUCA_OBmpTables( AStream, ANativeEndianStream, @@ -3410,7 +3483,34 @@ begin AddLine(ANonNativeEndianStream,' );' + sLineBreak); end; -//------------------------------------------- +procedure GenerateBinaryUCA_OBmpTables( + ANativeEndianStream, + ANonNativeEndianStream : TStream; + var AFirstTable : TucaOBmpFirstTable; + var ASecondTable : TucaOBmpSecondTable +); +var + i, j : Integer; + locLine : string; + wordValue : Word; + value : UInt24; +begin + for i := Low(AFirstTable) to High(AFirstTable) do begin + wordValue := AFirstTable[i]; + ANativeEndianStream.Write(wordValue,SizeOf(wordValue)); + ReverseBytes(wordValue,SizeOf(wordValue)); + ANonNativeEndianStream.Write(wordValue,SizeOf(wordValue)); + end; + + for i := Low(ASecondTable) to High(ASecondTable) do begin + for j := Low(TucaOBmpSecondTableItem) to High(TucaOBmpSecondTableItem) do begin + value := ASecondTable[i][j]; + ANativeEndianStream.Write(value,SizeOf(value)); + ReverseBytes(value,SizeOf(value)); + ANonNativeEndianStream.Write(value,SizeOf(value)); + end; + end; +end; type POBmpSecondTableItem = ^TOBmpSecondTableItem; @@ -4103,6 +4203,17 @@ begin Result := r; end; +procedure ReverseRecordBytes(var AItem : TSerializedCollationHeader); +begin + ReverseBytes(AItem.BMP_Table1Length,SizeOf(AItem.BMP_Table1Length)); + ReverseBytes(AItem.BMP_Table2Length,SizeOf(AItem.BMP_Table2Length)); + ReverseBytes(AItem.OBMP_Table1Length,SizeOf(AItem.OBMP_Table1Length)); + ReverseBytes(AItem.OBMP_Table2Length,SizeOf(AItem.OBMP_Table2Length)); + ReverseBytes(AItem.PropCount,SizeOf(AItem.PropCount)); + ReverseBytes(AItem.VariableLowLimit,SizeOf(AItem.VariableLowLimit)); + ReverseBytes(AItem.VariableHighLimit,SizeOf(AItem.VariableHighLimit)); +end; + procedure ReverseBytes(var AData; const ALength : Integer); var i,j : PtrInt; diff --git a/utils/unicode/unihelper.lpr b/utils/unicode/unihelper.lpr index 794f901b5d..f1b3de9e2e 100644 --- a/utils/unicode/unihelper.lpr +++ b/utils/unicode/unihelper.lpr @@ -31,7 +31,7 @@ program unihelper; {$mode objfpc}{$H+} -{$typedadress on} +{$typedaddress on} uses SysUtils, Classes, @@ -66,6 +66,7 @@ end; var dataPath, outputPath : string; stream, binStreamNE, binStreamOE, tmpStream : TMemoryStream; + binaryStreamNE, binaryStreamOE : TMemoryStream; hangulSyllables : TCodePointRecArray; ucaBook : TUCA_DataBook; ucaPropBook : PUCA_PropBook; @@ -95,6 +96,7 @@ var ucaoFirstTable : TucaoBmpFirstTable; ucaoSecondTable : TucaOBmpSecondTable; WL : Integer; + serializedHeader : TSerializedCollationHeader; begin WriteLn(SUsage+sLineBreak); if (ParamCount > 0) then @@ -125,6 +127,8 @@ begin Halt(1); end; + binaryStreamNE := nil; + binaryStreamOE := nil; binStreamOE := nil; binStreamNE := nil; tmpStream := nil; @@ -206,6 +210,8 @@ begin {$IFDEF UCA_TEST} uca_CheckProp_2y(ucaBook,ucaPropBook,@ucaoFirstTable,@ucaoSecondTable); {$ENDIF UCA_TEST} + binaryStreamNE := TMemoryStream.Create(); + binaryStreamOE := TMemoryStream.Create(); WriteLn('Generate UCA Props tables ...'); binStreamNE.Clear(); binStreamOE.Clear(); @@ -226,6 +232,37 @@ begin binStreamOE.SaveToFile(GenerateEndianIncludeFileName(s,ENDIAN_NON_NATIVE)); binStreamNE.Clear(); binStreamOE.Clear(); +// Binary DUCET + FillChar(serializedHeader,SizeOf(TSerializedCollationHeader),0); + serializedHeader.Version := ucaBook.Version; + serializedHeader.CollationName := 'DUCET';//'Default Unicode Collation Element Table (DUCET)'; + serializedHeader.VariableWeight := Ord(ucaBook.VariableWeight); + SetBit(serializedHeader.Backwards,0,ucaBook.Backwards[0]); + SetBit(serializedHeader.Backwards,1,ucaBook.Backwards[1]); + SetBit(serializedHeader.Backwards,2,ucaBook.Backwards[2]); + SetBit(serializedHeader.Backwards,3,ucaBook.Backwards[3]); + serializedHeader.BMP_Table1Length := Length(ucaFirstTable); + serializedHeader.BMP_Table2Length := Length(TucaBmpSecondTableItem) * + (Length(ucaSecondTable) * SizeOf(UInt24)); + serializedHeader.OBMP_Table1Length := Length(ucaoFirstTable) * SizeOf(Word); + serializedHeader.OBMP_Table2Length := Length(TucaOBmpSecondTableItem) * + (Length(ucaoSecondTable) * SizeOf(UInt24)); + serializedHeader.PropCount := ucaPropBook^.ItemSize; + serializedHeader.VariableLowLimit := ucaPropBook^.VariableLowLimit; + serializedHeader.VariableHighLimit := ucaPropBook^.VariableHighLimit; + binaryStreamNE.Write(serializedHeader,SizeOf(serializedHeader)); + ReverseRecordBytes(serializedHeader); + binaryStreamOE.Write(serializedHeader,SizeOf(serializedHeader)); + GenerateBinaryUCA_BmpTables(binaryStreamNE,binaryStreamOE,ucaFirstTable,ucaSecondTable); + GenerateBinaryUCA_OBmpTables(binaryStreamNE,binaryStreamOE,ucaoFirstTable,ucaoSecondTable); + GenerateBinaryUCA_PropTable(binaryStreamNE,binaryStreamOE,ucaPropBook); + binaryStreamNE.SaveToFile( + outputPath + Format('collation_ducet_%s.bco',[ENDIAN_SUFFIX[ENDIAN_NATIVE]]) + ); + binaryStreamOE.SaveToFile( + outputPath + Format('collation_ducet_%s.bco',[ENDIAN_SUFFIX[ENDIAN_NON_NATIVE]]) + ); +// Binary DUCET - END stream.Clear(); @@ -386,6 +423,8 @@ begin end; stream.SaveToFile(outputPath + 'diff2.txt'); finally + binaryStreamOE.Free(); + binaryStreamNE.Free(); tmpStream.Free(); binStreamOE.Free(); binStreamNE.Free();