Strange attribute value reported by FindFirst(), Attr = 2080 - delphi

When searching for files with FindFirst() I get an attribute value in the TSearchRec.Attr field of 2080. It is not specified in the help as there are only these values available and no combination of them yields 2080:
1 faReadOnly
2 faHidden
4 faSysFile
8 faVolumeID
16 faDirectory
32 faArchive
64 faSymLink
71 faAnyFile
Does anyone know what 2080 means and why I get that attribute value? The OS is XP embedded.

It turns out that the file found by FindFirst() was compressed and thus had the compressed bit set. Took me a while to figure out and I could not find a reference on the web that stated the actual value of TSearchRec.Attr when the compressed bit is set. Unclicking "Compress file" in the files advanced properties did the trick.

Attributes in TSearchRec map directly to the Windows file attributes used with the TWin32FindData record from FindFirstFile.
In hex (always render bit fields in hex, not decimal), 2080 is $0820, where it's clear there are two bits set. The lower bit corresponds to File_Attribute_Archive, or Delphi's faArchive, and the upper bit corresponds to File_Attribute_Compressed. It has no equivalent in the units that come with Delphi, but you can use the JclFileUtils.faCompressed symbol from the JCL.

In JclFileUtils unit from Jedi Code Library I found:
faNormalFile = $00000080;
...
faNotContentIndexed = $00002000;
If 2080 is in hex then this is it.
Look also at: http://www.tek-tips.com/viewthread.cfm?qid=1543818&page=9
EDIT:
While 2080 id decimal, and 2080 dec = 820 hex then attributes are combination of:
faArchive = $00000020;
faCompressed = $00000800;

This will extract the faDirectory bit and you dont have to worry about the compression bit set or not.
if ((sr.Attr AND faDirectory) <> 0) then
begin
.......
end;

Related

set of WideChar: Sets may have at most 256 elements

I have this line:
const
MY_SET: set of WideChar = [WideChar('A')..WideChar('Z')];
The above does not compile, with error:
[Error] Sets may have at most 256 elements
But this line does compile ok:
var WS: WideString;
if WS[1] in [WideChar('A')..WideChar('Z')] then...
And this also compiles ok:
const
MY_SET = [WideChar('A')..WideChar('Z'), WideChar('a')..WideChar('z')];
...
if WS[1] in MY_SET then...
Why is that?
EDIT: My question is why if WS[1] in [WideChar('A')..WideChar('Z')] compiles? and why MY_SET = [WideChar('A')..WideChar('Z'), WideChar('a')..WideChar('z')]; compiles? aren't they also need to apply to the set rules?
A valid set has to obey two rules:
Each element in a set must have an ordinal value less than 256.
The set must not have more than 256 elements.
MY_SET: set of WideChar = [WideChar('A')..WideChar('Z')];
Here you declare a set type (Set of WideChar) which has more than 256 elements -> Compiler error.
if WS[1] in [WideChar('A')..WideChar('Z')]
Here, the compiler sees WideChar('A') as an ordinal value. This value and all other values in the set are below 256. This is ok with rule 1.
The number of unique elements are also within limits (Ord('Z')-Ord('A')+1), so the 2nd rules passes.
MY_SET = [WideChar('A')..WideChar('Z'), WideChar('a')..WideChar('z')];
Here you declare a set that also fulfills the requirements as above. Note that the compiler sees this as a set of ordinal values, not as a set of WideChar.
A set can have no more than 256 elements.
Even with so few elements the set already uses 32 bytes.
From the documentation:
A set is a bit array where each bit indicates whether an element is in the set or not. The maximum number of elements in a set is 256, so a set never occupies more than 32 bytes. The number of bytes occupied by a particular set is equal to
(Max div 8) - (Min div 8) + 1
For this reason only sets of byte, (ansi)char, boolean and enumerations with fewer than 257 elements are possible.
Because widechar uses 2 bytes it can have 65536 possible values.
A set of widechar would take up 8Kb, too large to be practical.
type
Capitals = 'A'..'Z';
const
MY_SET: set of Capitals = [WideChar('A')..WideChar('Z')];
Will compile and work the same.
It does seem a bit silly to use widechar if your code ignores unicode.
As written only the English capitals are recognized, you do not take into account different locales.
In this case it would be better to use code like
if (AWideChar >= 'A') and (AWideChar <= 'Z') ....
That will work no matter how many chars fall in between.
Obviously you can encapsulate this in a function to save on typing.
If you insist on having large sets, see this answer: https://stackoverflow.com/a/2281327/650492

FindFirst and question mark

I need to delete all files, which names are started with "a", then three arbitrary letters and ".txt" extension like "a123.txt". Here is the code:
var
sFileMask: string;
tsrMessage: TSearchRec;
begin
sFileMask := 'c:/a???.txt';
if SysUtils.FindFirst(sFileMask, 0, tsrMessage) = 0 then
begin
repeat
ShowMessage(tsrMessage.Name);
until FindNext(tsrMessage) <> 0;
SysUtils.FindClose(tsrMessage);
end;
end;
I always thought that the question mark means one and only one character, but to my surprise found that this code returns "a.txt", "a1.txt" and "a123.txt" file names. Is there a simple way to modify the code for it to seek only files like "a123.txt"?
The simplest solution for your specific need is to replace this:
ShowMessage(tsrMessage.Name);
with this
if length(tsrMessage.Name)=8 then ShowMessage(tsrMessage.Name);
this will ensure that the length of the file name is exactly four characters + the period + the extension. Like David says, there's no way to have the API do this kind of filtering, so you'll have to do it yourself, but in your particular case, there's no need to enumerate the entire directory. You may at least let the API do the filtering it can do, and then do your own filtering on top of it.
EDIT: If you need to ensure that the three characters following the "a" are digits, you can do it this way:
if (length(tsrMessage.Name)=8) and tsrMessage[2].IsDigit and tsrMessage[3].IsDigit and tsrMessage[4].IsDigit then ShowMessage(tsrMessage.Name);
provided you are using a modern compiler (you'll need to include the "Characters" unit). Also take note that if you are compiling a mobile version, you'll need to use index [1], [2] and [3] instead, as they start index at 0 for strings.
If you are using an older version, you can do it like this:
function IsDigit(c : char) : boolean;
begin
Result:=(c>='0') and (c<='9')
end;
if (length(tsrMessage.Name)=8) and IsDigit(tsrMessage[2]) and IsDigit(tsrMessage[3]) and IsDigit(tsrMessage[4]) then ShowMessage(tsrMessage.Name);
This behaviour is as designed. It is explained by Raymond Chen here: How did wildcards work in MS-DOS?
You will see the exact same behaviour from the command interpreter.
C:\Desktop>dir a???.txt
Volume in drive C has no label.
Volume Serial Number is 20DA-7FEB
Directory of C:\Desktop
26/06/2016 14:03 6 a.txt
26/06/2016 14:03 6 a1.txt
26/06/2016 14:03 6 a12.txt
26/06/2016 14:03 6 a123.txt
4 File(s) 24 bytes
0 Dir(s) 286,381,445,120 bytes free
There is no way to persuade FindFirstFile (the API that is behind the RTL's FindFirst on Windows) to behave the way you wish. Your best option is to enumerate the entire directory, and perform your own filtering using your chosen pattern matching algorithm.

Getting the size in bytes of an arbitrary integer

Given an integer, 98749287 say, is there some built-in/libray function, either Erlang or Elixir, for getting the size in bytes?
To clarify, the minimum number of bytes used to represent the number in binary.
Seems simple, and have written a function using the "division by base" method and then counting bits, but after some hrs of searching docs havent found anything for what would seem useful to have.
If you have an unsigned integer, you can use the following snippet:
byte_size(binary:encode_unsigned(Integer))
Example:
1> byte_size(binary:encode_unsigned(3)).
1
2> byte_size(binary:encode_unsigned(256)).
2
3> byte_size(binary:encode_unsigned(98749287)).
4
Try this expression:
Value = (... your input ...),
NumBytes = size(integer_to_binary(Value, 2) + 7) div 8.
Reference: http://www.erlang.org/doc/man/erlang.html#integer_to_binary-2

How to create a long number of all bits at 1

I need to pass ~0L to my function, how can I do this, no matter what I do ~0 is being turned to -1
This is the C code:
812 int result = GetProperty(window, property_name,
813 (~0L), // (all of them)
814 &type, &format, &num_items, &properties);
This is my jsctypes:
var result = GetProperty(window, property_name, ctypes.long(~0), type.address(), format.address(), num_items.address(), properties.address()
Notice the ctypes.long(~0) how to make this be the 111111111111111111111111111111 for 32bit slash the 64 1's for 64bit?
Thanks
reference topic: What does (~0L) mean?
declare it unsigned long, ~0UL
Solution was to use ctypes.long(~0) this is good for 32 bit and 64 bit :) Thanks to #arai.
21:45 noida how to use ~0L in jsctypes?
22:07 arai noida: 32bit or 64bit?
22:11 noida can you show me how to do for both plz
22:17 arai noida: I guess ctypes.int32_t(~0) and ctypes.int64_t(~0) will work
22:20 noida -0x80000000
22:20 noida that wont work huh?
22:20 arai it uses ctypes.long for the parameter, so ctypes.long(~0) would be better
22:23 arai ~0L is 0xFFFFFFFFFFFFFFFF, right?
22:24 noida i thought it was: 0x7ffffff
22:29 arai printf("%lx\n", ~0L); outputs "ffffffffffffffff"
22:31 arai it would be more better to use ctypes.long(~0) for consistency
22:33 noida also using the long method will be cross 64/32 bit right?
22:37 arai "This automatically converts to an Int64 JavaScript object on all platforms, since it's unknown whether this is a 32-bit or 64-bit value. This is done for compatibility's sake."
22:37 arai https://developer.mozilla.org/en-US/docs/Mozilla/js-ctypes/js-ctypes_reference/ctypes

handling CMYK jpeg files in Delphi 7

I am trying to access files that are stored as Jpeg files, is there an easy way to display these image files without performance loss ?
You can load the JPeg file using an instance of TJPEGImage and then assign it to a TBitmap to display. You find TJPEGImage in unit jpeg.
jpeg := TJPEGImage.Create;
jpeg.LoadFromFile('filename.jpg');
bitm := TBitmap.Create;
bitm.Assign(jpeg);
Image1.Height := bitm.Height;
Image1.Width := bitm.Width;
Image1.Canvas.Draw(0, 0, bitm);
Alternatively, this should also work:
bitm := TBitmap.Create;
bitm.Assign('filename.jpg');
Image1.Height := bitm.Height;
Image1.Width := bitm.Width;
Image1.Canvas.Draw(0, 0, bitm);
I found this page!
http://cc.embarcadero.com/Item/19723
Enhanced jpeg implementation
Author: Gabriel Corneanu
This unit contains a new jpeg implementation (based on Delphi original)
fixed bug accessing one pixel height picture
added lossless transformation support for jpeg images (based on Thomas G. Lane C library - visit jpegclub.org/jpegtran )
added CMYK support (read only)
compiled for D5-2010 AND BCB5-6-CMYK to RGB fast MMX conversion (not for Delphi5, lack of MMX ASM) (fallback to simple pascal implementation if not available)
fixed bug in Delphi 5 ASM (CMYK to RGB function)
You only need the jpeg.dcu file; it can be copied to program directory or to the LIB directory.I generated obj and hpp files for use with CBuilder 5 and 6 also.This is what you need to use it:
This is just an enum
TJpegTransform = (
jt_FLIP_H, { horizontal flip }
jt_FLIP_V, { vertical flip }
jt_TRANSPOSE, { transpose across UL-to-LR axis }
jt_TRANSVERSE, { transpose across UR-to-LL axis }
jt_ROT_90, { 90-degree clockwise rotation }
jt_ROT_180, { 180-degree rotation }
jt_ROT_270 { 270-degree clockwise (or 90 ccw) }
);
procedure Crop(xoffs, yoffs, newwidth, newheight: integer); this method is cropping the image
procedure Transform(Operation: TJpegTransform);this method is applying the specified transformation; read the transupp.h comments about limitations(my code is using crop option)
property IsCMYK: boolean read FIsCMYK; this will indicate if the last jpeg image loaded is CMYK encoded
property InverseCMYK: boolean read FInverseCMYK write SetInverseCMYK;if set (default, because I could only find this kind of images), the CMYK image is decoded with inversed CMYK values (I read that Photoshop is doing this).
The jpegex is the same unit compiled with a different name. It can be used to avoid conflicts when you have other components without source code linking to the original jpeg unit. In this case you might need to use qualified class names to solve names conflict: jpegex.TJpegImage.xxx. Be carefull when you use both versions in one program: even though the classes have the same name, they are not identical and you can't cast or assign them directly. The only way to exchange data is saving to/loading from a stream.
Send comments to:
gabrielcorneanuATyahooDOTcom
I dont believe D7 can handle CMYK JPEG's.
If you cant open it using the JPEG unit as Ralph posted, you might consider using something like GDI+ to load the graphic file.
Actually, I once modified Jpeg.pas unit to partial CMYK support. Basically after
jpeg_start_decompress(jc.d)
you should check
if jc.d.out_color_space = JCS_CMYK then
and if true following jpeg_read_scanlines will get 4 bytes data instead of 3 bytes.
Also cinfo.saw_Adobe_marker indicates inverted values (probably Adobe was first who introduced CMYK jpeg variation).
But the most difficult part is CMYK-RGB conversion. Since there's no universal formula, in best systems it's always table approach. I tried to find some simple approximation, but there's always a picture that does not fit. Just as an example, don't use this formulas as a reference:
R_:=Max(254 - (111*C + 2*M + 7*Y + 36*K) div 128, 0);
G_:=Max(254 - (30*C + 87*M + 15*Y + 30*K) div 128, 0);
B_:=Max(254 - (15*C + 44*M + 80*Y + 24*K) div 128, 0);
Easy!
I implemented the CMYK conversion in the JPEG.PAS
Include it in your project to handle CMYK JPEG's
Get it here:
http://delphi.andreotti.nl/

Resources