UTI & files

I have read teh pages in the book about UTIs. I want to be able to write to a TextOutputStream (or if I have to a binary stream) to a path/filename that is fixed (no GetSaveFolderItem). but when I do, all my output files are of type TEXT and not my custom filetype. The custom filetype is created inside the app. I am obviously missing a step here.

how can i create the text file with my custom filetype?

thanks
sb

May I ask what you need to have a custom filetype for that the file extension itself cannot identify?

Remember for all intents… a file on disk is a collection of bytes… they are not “text” they are “data”. The program that reads it decides it that data is appropriate to use… and deals with it accordingly. The concept of “text” vs “data” is purely from a human interface point of view.

Scott, did you set the filetype of the file after writing it out with TextOutputStream? And/or did you add the appropriate extension to your filename? And yeah, there seems to be a little bit of voodoo with this stuff. I remember being similarly frustrated the last time I did this but can’t remember what the particular issue ended up being.

“how can i create the text file with my custom filetype?”
As I understand it, that question doesn’t make sense. A text file is…well…a text file. Maybe that is the problem. If you want a text file created via a textOutputStream, then it will be a text file. If you want a custom file type, then make sure you have done all of the above suggestions including creating an entry in your FileTypes class.

I have a custom filetype. it follows the instructions in the UserGuide. I have manually added that XML code about the filetype (copy/pasted/edited) from the UserGuide into the info.plist file.

my issue (and it is between the ears) is I dont know how to assign the filetype to the file once it is created. Or as it is created.

dont know how to set/assign the filetype after writing. And the file has the proper extension.

a .doc file is a binary file. a .sqlite file is a binary file. You can’t open either with a text editor and read the contents.
an .xml file is a text file. an .html file is a text file. both you can open in a text editor and read the contents.

now my file is a data file that is pure text (specifically formatted for the application).

how can you write to a custom filetype a bunch of text if you dont use TextOutputStream? this is not me being confrontational but just not knowing the answer.

am I being clear? or clear as mud?

For older versions of OS X you can get away with setting just the type & / creator
However, the RIGHT way is to , in your applications plist, declare an exported UTI type that define the icon, extension, etc.

And yes, there’s no simple way to define that right in the IDE
I think Sam’s app wrapper mini has a way to do this
And there may be some post build scripts around that do this

Oh right! Thanks for the reminder Norman. The way I solve this is from app.Open to find my plist, read it in, search for the UTI block. If not found, do a quick insert, then save. This patches things up every time in Debug builds, and the first time an actual build is run. Here’s an app method that does this:

[code]Sub CheckInfoPlist()
dim fi, infoPlist as FolderItem
dim tis as TextInputStream
dim tos as TextOutputStream
dim s, s1, s2 as string
dim patched as Boolean

fi = me.ExecutableFile
fi = fi.Parent
fi = fi.Parent
infoPlist = fi.Child(“Info.plist”)

// MsgBox(infoPlist.AbsolutePath)

if infoPlist <> nil and infoPlist.Exists then
patched = false

tis = TextInputStream.Open(infoPlist)
if tis <> nil then
  s = tis.ReadAll
  tis.Close
  tis = nil
end if

s = ReplaceLineEndings(s, EndOfLine.UNIX)
s1 = ReplaceLineEndings(info_plist_patch, EndOfLine.UNIX)

if s.InStr(s1) <= 0 then
  s2 = "</dict>" + EndOfLine.UNIX + "</plist>"
  s = s.Replace(s2, s1 + EndOfLine.UNIX + s2)
  patched = true
end if

if patched then
  Speak "Patched"
  
  tos = TextOutputStream.Create(infoPlist)
  if tos <> nil then
    tos.Write(s)
    tos.Close
    tos = nil
  end if
end if

end if

End Sub
[/code]

[quote=24346:@Norman Palardy]For older versions of OS X you can get away with setting just the type & / creator
However, the RIGHT way is to , in your applications plist, declare an exported UTI type that define the icon, extension, etc.[/quote]

I am using a UTI that is defined in my Info.plist file. I followed the example in the book. Is it correct? dont know since it is not working.

[quote=24346:@Norman Palardy]And yes, there’s no simple way to define that right in the IDE
I think Sam’s app wrapper mini has a way to do this
And there may be some post build scripts around that do this[/quote]

I used Sam’s App Wrapper (not mini) and I get the same results. The file with the .customextension extension is coming as a plain-old-text-file. if I do a mdls on the file it says TEXT.

kaylee-mobile-ncm:wrapped sboss$ mdls .DS_Store*sums kMDItemFSContentChangeDate = 2013-08-01 16:44:06 +0000 kMDItemFSCreationDate = 2013-08-01 16:44:06 +0000 kMDItemFSCreatorCode = "ttxt" kMDItemFSFinderFlags = 0 kMDItemFSHasCustomIcon = 0 kMDItemFSInvisible = 1 kMDItemFSIsExtensionHidden = 0 kMDItemFSIsStationery = 0 kMDItemFSLabel = 0 kMDItemFSName = ".DS_Store.checksums" kMDItemFSNodeCount = 328 kMDItemFSOwnerGroupID = 80 kMDItemFSOwnerUserID = 501 kMDItemFSSize = (null) kMDItemFSTypeCode = "TEXT"

i know it is something very simple that I am missing. it is always something simple.

[quote=24352:@Brad Hutchings]Oh right! Thanks for the reminder Norman. The way I solve this is from app.Open to find my plist, read it in, search for the UTI block. If not found, do a quick insert, then save. This patches things up every time in Debug builds, and the first time an actual build is run. Here’s an app method that does this:
[/quote]

Brad thanks for that. I will add that to my app.

Well is it defined as an Exported File type UTI ?
And for your app to open it on a drag & drop you may also need it set up in Document Types
Can’t tell from what you’ve posted
The actual Plist would be useful

[quote=24352:@Brad Hutchings]Brad Hutchings 49 minutes ago Alpha Testers, Beta Testers
Oh right! Thanks for the reminder Norman. The way I solve this is …[/quote]

Very nice, Brad! Thanks for that.

wrapped with App Wrapper

[code]<?xml version="1.0" encoding="UTF-8"?>

AppWrapperVersion 2.1.2 (165) CFBundleDevelopmentRegion en CFBundleDocumentTypes CFBundleTypeIconFile ChecksumsDocType.icns CFBundleTypeName checksums CFBundleTypeRole None LSItemContentTypes com.nocturnalcodingmonkeys.checksums.doc LSTypeIsPackage CFBundleTypeIconFile ChecksumsDocType.icns CFBundleTypeName ChecksumsDocType CFBundleTypeRole Viewer LSItemContentTypes com.nocturnalcodingmonkeys.checksums.doc LSTypeIsPackage CFBundleExecutable NCM checksums CFBundleGetInfoString CFBundleIconFile NCM checksums.icns CFBundleIdentifier com.nocturnalcodingmonkeys.checksums CFBundleInfoDictionaryVersion 6.0 CFBundleName NCM checksums CFBundlePackageType APPL CFBundleShortVersionString 0.1.0 CFBundleSignature CFBundleVersion 25 LSApplicationCategoryType public.app-category.utilities LSMinimumSystemVersion 10.6.0 UTExportedTypeDeclarations UTTypeConformsTo public.data public.item UTTypeDescription checksums UTTypeIconFile ChecksumsDocType.icns UTTypeIdentifier com.nocturnalcodingmonkeys.checksums.doc UTTypeTagSpecification public.filename-extension checksums [/code]

manually edited.

[code]<?xml version="1.0" encoding="UTF-8"?>

CFBundleExecutable NCM checksums CFBundleName NCM checksums CFBundleIdentifier com.nocturnalcodingmonkeys.checksums CFBundleInfoDictionaryVersion 6.0 CFBundleVersion 0.1.0.2.25 CFBundleDevelopmentRegion en CFBundlePackageType APPL CFBundleSignature CFBundleGetInfoString CFBundleShortVersionString CFBundleIconFile NCM checksums.icns LSMinimumSystemVersion 10.6.0 CFBundleDocumentTypes CFBundleTypeName checksums CFBundleTypeIconFile Untitled.icns CFBundleTypeOSTypes ??? CFBundleTypeExtensions checksums LSItemContentTypes com.nocturnalcodingmonkeys.checksums.doc CFBundleTypeRole None CFBundleTypeName ChecksumsDocType CFBundleTypeIconFile ChecksumsDocType.icns CFBundleTypeOSTypes **** CFBundleTypeExtensions checksums LSItemContentTypes com.nocturnalcodingmonkeys.checksums.doc CFBundleTypeRole Viewer UTExportedTypeDeclarations UTTypeConformsTo public.data public.item UTTypeIdentifier com.nocturnalcodingmonkeys.checksums.doc UTTypeTagSpecification public.checksums checksums [/code]

[quote=24373:@Peter Truskier]Very nice, Brad! Thanks for that.
[/quote]

You’re welcome. It is, however, a terrible and convenient hack that happens to solve a particular simple instance of a problem. I originally did something like this in 2006-ish and am surprised the approach still sorta works. So use with caution going forward.

Correct me if I’m wrong, but Xojo sets the creator and type codes to ttxt and TEXT on files created with textoutputstream, even though MacType is depricated… try adding this
f.MacCreator="???"
f.MacType="???"
after closing the new textoutputstream. Not sure if it will fix the problem, but it might help see what’s really going on.

Bear in mind Brads approach would break a sandboxed app. You can’t change the info.plist file once an app is sandboxed.

I had an abosolute headache with this and it is something which would be nice to have in the IDE to save all the grief. On one of my apps where I have the file types associated with my app and they have a document Icon associated with them the XML you need in your info.plist file is as follows: (obviously change your extensions and icons etc to suit.)


<key>CFBundleDocumentTypes</key>
	<array>
		<dict>
			<key>CFBundleTypeExtensions</key>
			<array>
				<string>ofx</string>
			</array>
			<key>CFBundleTypeIconFile</key>
			<string>OFXIcon.icns</string>
			<key>CFBundleTypeName</key>
			<string>Open Financial Exchange (OFX)</string>
			<key>CFBundleTypeRole</key>
			<string>Viewer</string>
		</dict>
		<dict>
			<key>CFBundleTypeExtensions</key>
			<array>
				<string>qif</string>
			</array>
			<key>CFBundleTypeIconFile</key>
			<string>QIFIcon.icns</string>
			<key>CFBundleTypeName</key>
			<string>Quicken Interchange Format (QIF)</string>
			<key>CFBundleTypeRole</key>
			<string>Viewer</string>
		</dict>
	</array>

[quote=24382:@jim mckay]Correct me if I’m wrong, but Xojo sets the creator and type codes to ttxt and TEXT on files created with textoutputstream, even though MacType is depricated… try adding this
f.MacCreator="???"
f.MacType="???"
after closing the new textoutputstream. Not sure if it will fix the problem, but it might help see what’s really going on.[/quote]

mdls

kMDItemFSContentChangeDate = 2013-08-01 17:33:10 +0000 kMDItemFSCreationDate = 2013-08-01 17:33:10 +0000 kMDItemFSCreatorCode = "????" kMDItemFSFinderFlags = 0 kMDItemFSHasCustomIcon = 0 kMDItemFSInvisible = 1 kMDItemFSIsExtensionHidden = 0 kMDItemFSIsStationery = 0 kMDItemFSLabel = 0 kMDItemFSName = ".DS_Store.checksums" kMDItemFSNodeCount = 328 kMDItemFSOwnerGroupID = 80 kMDItemFSOwnerUserID = 501 kMDItemFSSize = (null) kMDItemFSTypeCode = "????"

so it changed those two fields but nothing changed. when double clicking the file or using open on the cli, it opens in TextEdit.

the question of the minute is, do I switch from TextOutputStream to BinaryStream? do you think that is where I am getting hosed?

[quote=24384:@Mike Charlesworth]Bear in mind Brads approach would break a sandboxed app. You can’t change the info.plist file once an app is sandboxed.
[/quote]

Note that my approach doesn’t change the plist after the app is sandboxed if you run the app once before doing the sandbox magic.

An in my example above with the XML, just for clarity in my FileTypes within the app I have:

For OFX:

DisplayName: Open Financial Exchange (OFX)
ObjectName: OpenFinancialExchange
Extensions: OFX

Thats all, no MacType, no MacCreator, no UTI, no Icon.

It works.

I think this is the problem

[quote=24374:@scott boss]

UTTypeTagSpecification

public.checksums

checksums
[/quote]

I think the UTTypeTagSpecification should list

<key>UTTypeTagSpecification</key> <dict> <key>public.filename-extension</key> <array> <string>checksums</string> </array>
this tells the OS that the thing that identifies your custom type is the extension