IdHeaderCoderBase.pas 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. unit IdHeaderCoderBase;
  2. interface
  3. {$i IdCompilerDefines.inc}
  4. uses
  5. Classes, IdGlobal, IdException;
  6. type
  7. TIdHeaderDecodingNeededEvent = procedure(const ACharSet: String; const AData: TIdBytes; var VResult: String; var VHandled: Boolean) of object;
  8. TIdHeaderEncodingNeededEvent = procedure(const ACharSet, AData: String; var VResult: TIdBytes; var VHandled: Boolean) of object;
  9. TIdHeaderCoder = class(TObject)
  10. public
  11. class function Decode(const ACharSet: String; const AData: TIdBytes): String; virtual;
  12. class function Encode(const ACharSet, AData: String): TIdBytes; virtual;
  13. class function CanHandle(const ACharSet: String): Boolean; virtual;
  14. end;
  15. TIdHeaderCoderClass = class of TIdHeaderCoder;
  16. EIdHeaderEncodeError = class(EIdException);
  17. var
  18. GHeaderEncodingNeeded: TIdHeaderEncodingNeededEvent = nil;
  19. GHeaderDecodingNeeded: TIdHeaderDecodingNeededEvent = nil;
  20. function HeaderCoderByCharSet(const ACharSet: String): TIdHeaderCoderClass;
  21. function DecodeHeaderData(const ACharSet: String; const AData: TIdBytes; var VResult: String): Boolean;
  22. function EncodeHeaderData(const ACharSet, AData: String): TIdBytes;
  23. procedure RegisterHeaderCoder(const ACoder: TIdHeaderCoderClass);
  24. procedure UnregisterHeaderCoder(const ACoder: TIdHeaderCoderClass);
  25. implementation
  26. uses
  27. {$IFDEF VCL_XE3_OR_ABOVE}
  28. System.Types,
  29. {$ENDIF}
  30. {$IFDEF HAS_UNIT_Generics_Collections}
  31. System.Generics.Collections,
  32. {$ENDIF}
  33. SysUtils, IdResourceStringsProtocols;
  34. type
  35. TIdHeaderCoderList = class(TList{$IFDEF HAS_GENERICS_TList}<TIdHeaderCoderClass>{$ENDIF})
  36. public
  37. function ByCharSet(const ACharSet: String): TIdHeaderCoderClass;
  38. end;
  39. var
  40. GHeaderCoderList: TIdHeaderCoderList = nil;
  41. { TIdHeaderCoder }
  42. class function TIdHeaderCoder.Decode(const ACharSet: String; const AData: TIdBytes): String;
  43. begin
  44. Result := '';
  45. end;
  46. class function TIdHeaderCoder.Encode(const ACharSet, AData: String): TIdBytes;
  47. begin
  48. Result := nil;
  49. end;
  50. class function TIdHeaderCoder.CanHandle(const ACharSet: String): Boolean;
  51. begin
  52. Result := False;
  53. end;
  54. { TIdHeaderCoderList }
  55. function TIdHeaderCoderList.ByCharSet(const ACharSet: string): TIdHeaderCoderClass;
  56. var
  57. I: Integer;
  58. LCoder: TIdHeaderCoderClass;
  59. begin
  60. Result := nil;
  61. // loop backwards so that user-defined coders can override native coders
  62. for I := Count-1 downto 0 do begin
  63. LCoder := TIdHeaderCoderClass(Items[I]);
  64. if LCoder.CanHandle(ACharSet) then begin
  65. Result := LCoder;
  66. Exit;
  67. end;
  68. end;
  69. end;
  70. function HeaderCoderByCharSet(const ACharSet: String): TIdHeaderCoderClass;
  71. begin
  72. if Assigned(GHeaderCoderList) then begin
  73. Result := GHeaderCoderList.ByCharSet(ACharSet);
  74. end else begin
  75. Result := nil;
  76. end;
  77. end;
  78. function DecodeHeaderData(const ACharSet: String; const AData: TIdBytes; var VResult: String): Boolean;
  79. var
  80. LCoder: TIdHeaderCoderClass;
  81. begin
  82. LCoder := HeaderCoderByCharSet(ACharSet);
  83. if LCoder <> nil then begin
  84. VResult := LCoder.Decode(ACharSet, AData);
  85. Result := True;
  86. end else
  87. begin
  88. VResult := '';
  89. Result := False;
  90. if Assigned(GHeaderDecodingNeeded) then begin
  91. GHeaderDecodingNeeded(ACharSet, AData, VResult, Result);
  92. end;
  93. { RLebeau: TODO - enable this?
  94. if not LDecoded then begin
  95. raise EIdHeaderDecodeError.Create(RSHeaderDecodeError, [ACharSet]);
  96. end;
  97. }
  98. end;
  99. end;
  100. function EncodeHeaderData(const ACharSet, AData: String): TIdBytes;
  101. var
  102. LCoder: TIdHeaderCoderClass;
  103. LEncoded: Boolean;
  104. begin
  105. LCoder := HeaderCoderByCharSet(ACharSet);
  106. if LCoder <> nil then begin
  107. Result := LCoder.Encode(ACharSet, AData);
  108. end else
  109. begin
  110. Result := nil;
  111. LEncoded := False;
  112. if Assigned(GHeaderEncodingNeeded) then begin
  113. GHeaderEncodingNeeded(ACharSet, AData, Result, LEncoded);
  114. end;
  115. if not LEncoded then begin
  116. raise EIdHeaderEncodeError.CreateFmt(RSHeaderEncodeError, [ACharSet]);
  117. end;
  118. end;
  119. end;
  120. procedure RegisterHeaderCoder(const ACoder: TIdHeaderCoderClass);
  121. begin
  122. if Assigned(ACoder) and
  123. Assigned(GHeaderCoderList) and
  124. (GHeaderCoderList.IndexOf(
  125. {$IFDEF HAS_GENERICS_TList}ACoder{$ELSE}TObject(ACoder){$ENDIF}
  126. ) = -1) then
  127. begin
  128. GHeaderCoderList.Add(
  129. {$IFDEF HAS_GENERICS_TList}ACoder{$ELSE}TObject(ACoder){$ENDIF}
  130. );
  131. end;
  132. end;
  133. procedure UnregisterHeaderCoder(const ACoder: TIdHeaderCoderClass);
  134. begin
  135. if Assigned(GHeaderCoderList) then begin
  136. GHeaderCoderList.Remove(
  137. {$IFDEF HAS_GENERICS_TList}ACoder{$ELSE}TObject(ACoder){$ENDIF}
  138. );
  139. end;
  140. end;
  141. initialization
  142. GHeaderCoderList := TIdHeaderCoderList.Create;
  143. finalization
  144. FreeAndNil(GHeaderCoderList);
  145. end.