Recent

Author Topic: Read out File Attribute Hidden on macOS  (Read 2497 times)

LazProgger

  • Full Member
  • ***
  • Posts: 103
Read out File Attribute Hidden on macOS
« on: August 28, 2019, 02:34:44 am »
I am trying to read out whether a file is hidden on macOS. For that, I have translated the following code from swift:

Code: Pascal  [Select][+][-]
  1. function MacGetFileAttributeHidden(AFileName: string): boolean;
  2. var
  3.   ANSFileURL: NSURL;
  4.   ANSFile: NSString;
  5.   XXX: NSNumber; // not working
  6. begin
  7.   ANSFile := NSSTR(pchar(AFileName));
  8.   ANSFileURL := NSURL.fileURLWithPath(ANSFile);
  9.  
  10.   if ANSFileURL.getResourceValue_forKey_error(XXX, NSURLIsHiddenKey, nil) then begin
  11.       result := NSNumber(XXX).integerValue = 1;
  12.   end else begin
  13.       result := false;
  14.   end;
  15.  
  16.   ANSFile.release;
  17. end;

The swift code is as follows:

Code: C  [Select][+][-]
  1. let myUrl = NSURL(fileURLWithPath: "my/path")
  2. var isHidden: AnyObject?
  3. do {
  4.   try myUrl.getResourceValue(&isHidden, forKey: NSURLIsHiddenKey)
  5.   return (isHidden as? NSNumber)?.boolValue ?? false
  6. } catch let error as NSError {
  7.   print(error.debugDescription)
  8.   return false
  9. }

Source: https://stackoverflow.com/questions/34741823/cocoa-swift-get-set-hidden-flag-on-files-and-directories

The only thing, the compiler is complaining about is the "isHidden" variable which is of type "AnyObject" in swift. There seems to be no type of this kind in Lazarus and the function getResourceValue_forKey_error requires the type "idPtr". In the code above I have written this variable as XXX.

Can someone help me with that? Of course, also other improvements of that code are welcome.
« Last Edit: August 28, 2019, 03:04:15 am by LazProgger »

dbannon

  • Hero Member
  • *****
  • Posts: 2786
    • tomboy-ng, a rewrite of the classic Tomboy
Re: Read out File Attribute Hidden on macOS
« Reply #1 on: August 28, 2019, 05:27:03 am »
how about using function FileGetAttrUTF8(const FileName: String): Longint; from LazFileUtils ?

FileGetAttr returns the attribute settings of file FileName. The attribute is a OR-ed combination of the following constants:
faReadOnly  - The file is read-only.
faHidden - The file is hidden. (On unix, this means that the filename starts with a dot)
faSysFile - The file is a system file (On unix, this means that the file is a character, block or FIFO file).
faVolumeId - Volume Label. Only for DOS/Windows on a plain FAT (not VFAT or Fat32) filesystem.
faDirectory - File is a directory.

faArchive - file should be archived. Not possible on Unix

Davo
Lazarus 3, Linux (and reluctantly Win10/11, OSX Monterey)
My Project - https://github.com/tomboy-notes/tomboy-ng and my github - https://github.com/davidbannon

Bart

  • Hero Member
  • *****
  • Posts: 5275
    • Bart en Mariska's Webstek
Re: Read out File Attribute Hidden on macOS
« Reply #2 on: August 28, 2019, 02:01:16 pm »
Since MacOS is unix, hidden files/folders start their names with a period ('.').
I'm not sure if FileGetAttribute sets faHidden on *nix filenames.

Bart

dbannon

  • Hero Member
  • *****
  • Posts: 2786
    • tomboy-ng, a rewrite of the classic Tomboy
Re: Read out File Attribute Hidden on macOS
« Reply #3 on: August 28, 2019, 02:04:32 pm »
yep, according to help files, a dot file is presented as faHidden.
but i have not used it myself.
Davo
Lazarus 3, Linux (and reluctantly Win10/11, OSX Monterey)
My Project - https://github.com/tomboy-notes/tomboy-ng and my github - https://github.com/davidbannon

LazProgger

  • Full Member
  • ***
  • Posts: 103
Re: Read out File Attribute Hidden on macOS
« Reply #4 on: August 28, 2019, 04:45:15 pm »
Using faHidden was my first approach, but it is not leading to results.

You can set a hidden flag in maOS in the following way:

Code: C  [Select][+][-]
  1. // Create an NSURL object
  2. let url = NSURL(fileURLWithPath: "/path/to/some/file.txt")!
  3.  
  4. // Setting isHidden
  5. let isHidden = NSNumber(bool: true)
  6. if !url.setResourceValue(isHidden, forKey: NSURLIsHiddenKey, error: &error) {
  7.     println(error?.localizedDescription)
  8. }

Source: https://stackoverflow.com/questions/34741823/cocoa-swift-get-set-hidden-flag-on-files-and-directories

This only seems to set a flag for "hidden", it does not change the file name. So, we cannot rely on the file name here.

My code in my initial post should be able to read it out, but I don't know with which variable type.
« Last Edit: August 28, 2019, 04:51:13 pm by LazProgger »

Jonas Maebe

  • Hero Member
  • *****
  • Posts: 1058
Re: Read out File Attribute Hidden on macOS
« Reply #5 on: August 28, 2019, 07:14:45 pm »
There seems to be no type of this kind in Lazarus and the function getResourceValue_forKey_error requires the type "idPtr".
The equivalent of "idPtr" in FPC is (objc.)id.

LazProgger

  • Full Member
  • ***
  • Posts: 103
Re: Read out File Attribute Hidden on macOS
« Reply #6 on: August 28, 2019, 09:00:06 pm »
The equivalent of "idPtr" in FPC is (objc.)id.

How can I use this?

I get the error "identifier expected but ')' found" with this:

Code: Pascal  [Select][+][-]
  1. ANSFileURL.getResourceValue_forKey_error((XXX.)id., NSURLIsHiddenKey, nil)



« Last Edit: August 28, 2019, 09:02:26 pm by LazProgger »

Jonas Maebe

  • Hero Member
  • *****
  • Posts: 1058
Re: Read out File Attribute Hidden on macOS
« Reply #7 on: August 28, 2019, 09:12:37 pm »
The equivalent of "idPtr" in FPC is (objc.)id.

How can I use this?

I get the error "identifier expected but ')' found" with this:

Code: Pascal  [Select][+][-]
  1. ANSFileURL.getResourceValue_forKey_error((XXX.)id., NSURLIsHiddenKey, nil)

"id" is a type. You just declare the type of your variable as "id". You may also want to have a look at https://wiki.freepascal.org/FPC_PasCocoa#The_id_type

LazProgger

  • Full Member
  • ***
  • Posts: 103
Re: Read out File Attribute Hidden on macOS
« Reply #8 on: August 28, 2019, 09:39:37 pm »
Hm...

When declared as "id", it does not compile and gives the error "Got 'id' expected 'idptr'".

When declared as "idptr", it compiles but it results in an access violation when running the code. :/

Jonas Maebe

  • Hero Member
  • *****
  • Posts: 1058
Re: Read out File Attribute Hidden on macOS
« Reply #9 on: August 28, 2019, 09:47:45 pm »
idptr is a pointer to a variable whose type is "id". If you just declare a variable of this type and don't initialise it, it will point to random memory. When the called routine tries to write to this memory, crashing is indeed the most likely consequence. Try passing the address of a variable of the type "id".

LazProgger

  • Full Member
  • ***
  • Posts: 103
Re: Read out File Attribute Hidden on macOS
« Reply #10 on: August 29, 2019, 03:47:38 am »
idptr is a pointer to a variable whose type is "id". If you just declare a variable of this type and don't initialise it, it will point to random memory. When the called routine tries to write to this memory, crashing is indeed the most likely consequence. Try passing the address of a variable of the type "id".

Unfortunately, I'm neither an expert in pointers nor in macOS coding.

According to your suggestions, I have tried the following:

Code: Pascal  [Select][+][-]
  1. function MacGetFileAttributeHidden(AFileName: string): boolean;
  2. var
  3.   ANSFileURL: NSURL;
  4.   ANSFile: NSString;
  5.   AValue: id;
  6. begin
  7.   ANSFile := NSSTR(pchar(AFileName));
  8.   ANSFileURL := NSURL.fileURLWithPath(ANSFile);
  9.  
  10.   // AValue := 0; AValue := nil; AValue := NSNumber.alloc.init; AValue := id.init; AValue := id.alloc.init; <- not working
  11.  
  12.   if ANSFileURL.getResourceValue_forKey_error(Pointer(AValue), NSURLIsHiddenKey, nil) then begin // <- exception here
  13.       // result := NSNumber(XXX).integerValue = 1;
  14.   end else begin
  15.       result := false;
  16.   end;
  17.  
  18.   ANSFile.release;
  19. end;

When passing Pointer(AValue) it is compiling but throwing an exception at run-time.
I have tried to init AValue using different methods that can be seen above. Unfortunately, none of them is working. The first 2 can be compiled but are throwing an exception at run-time, the others are not possible to be compiled.

I have also tried to declare AValue as NSNumber which is also compiling, but it also results in an exception at run-time.

Any idea what can be done here?
« Last Edit: August 29, 2019, 03:54:46 am by LazProgger »

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2770
    • havefunsoft.com
Re: Read out File Attribute Hidden on macOS
« Reply #11 on: August 29, 2019, 04:25:41 am »
you need to use @Value.

Here's a basic example:
Code: Pascal  [Select][+][-]
  1. program project1;
  2.  
  3. {$mode objfpc}{$H+}
  4. {$modeswitch objectivec2}
  5.  
  6. uses
  7.   cthreads, Classes, CocoaAll;
  8.  
  9. var
  10.   pool : NSAutoreleasePool;
  11.   url  : NSURL;
  12.   vl   : NSObject;
  13.   str  : string;
  14. begin
  15.   if ParamCount=0 then str := ParamStr(0)
  16.   else str := ParamStr(1);
  17.  
  18.   pool := NSAutoreleasePool.alloc.init;
  19.   url := NSURL.fileURLWithPath(NSString.stringWithUTF8String(@str[1]));
  20.   url.getResourceValue_forKey_error(@vl, NSURLIsHiddenKey, nil);
  21.   if Assigned(vl) then begin
  22.     writeln('class: ',vl.className.UTF8String);
  23.     if (vl.isKindOfClass(NSNumber))   then
  24.       writeln('value: ', NSNumber(vl).boolValue);
  25.   end;
  26.   pool.release;
  27. end.
  28.  
whenever you see "out" in ObjC parameters, that pretty much means you'll need to pass the address of your variable

For this particular case the returned "value" is expected to be NSNumber. Thus using NSNumber as type (instead of "id" or NSObject) for vl variable, is fine. (and can save you some time on type-checking)

In general, it can be of any type. (that's why there's a check for isKindOfClass NSNumber).
You don't need to ".release" the returned value.
« Last Edit: August 29, 2019, 04:30:27 am by skalogryz »

LazProgger

  • Full Member
  • ***
  • Posts: 103
Re: Read out File Attribute Hidden on macOS
« Reply #12 on: August 29, 2019, 04:50:30 pm »
Thank you very much! Your example helped me a lot! It's working with @ and I have learned much about objectivecs type conversions with your code.

It would be great if you could answer my following background questions:

Do we need the NSAutoreleasePool in a GUI application?
I have searched for that and according to https://stackoverflow.com/questions/3659196/why-use-nsautoreleasepool it seems as if this is only necessary in console applications like your example is one. The code is also working without the NSAutoreleasePool lines in a GUI application. Or is it better to include it?

You don't need to ".release" the returned value.

When do we need .release at all?
In my initial code I had also used ANSFile.release. Of course, your code using NSString.stringWithUTF8String(@str[1]) is better than my approach, but do we need .release for NSString, NSArray, NSPasteboard and so on at the end of a function using them? Or can we omit it? Or should we only use it when we have called a .alloc.init? Probably this is also related to NSAutoreleasePool ?!
« Last Edit: August 29, 2019, 04:52:04 pm by LazProgger »

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2770
    • havefunsoft.com
Re: Read out File Attribute Hidden on macOS
« Reply #13 on: August 30, 2019, 12:56:03 am »
Do we need the NSAutoreleasePool in a GUI application?
On the highlevel - no, you don't need to use NSAutoreleasePool.
Every GUI application event is already wrapped in its own NSAutoreleasePool.

When do we need .release at all?
if you use explicit "alloc" call to create an object.
In your code, you're not using "alloc", instead you're using a class method fileURLWithPath.

Using the method promises that you don't have to make the release and not to have a memory leak.
(typically it's flagging the object for autorelease with the next releasing pool. OR the object could be a "global" object of some sort. Whatever it is - you must not "release" it, if you didn't allocate it) .

This is a Memory management practice describe in Apple's document:
https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html#//apple_ref/doc/uid/20000994-SW1
(currently it's in some sort of deprecation as Objectice-C 2.0 language manages memory for the developer)
Some information here:
https://wiki.freepascal.org/Cocoa_Internals/Memory_Management

LazProgger

  • Full Member
  • ***
  • Posts: 103
Re: Read out File Attribute Hidden on macOS
« Reply #14 on: August 30, 2019, 02:10:55 am »
@skalogryz: Thank you very much for clarification.

 

TinyPortal © 2005-2018