How to convert Path to 8.3 format with Inno Setup - delphi

I need to get 8.3 formatted path (in this case {app}) for registry entry.
Unfortunately this specific Delphi function does not work in Inno Setup
function ExtractShortPathName(const S: FullFileName): string;

Use the GetShortName function. From the reference:
Returns the short version of the specified long filename. If the short
version of the long filename is not found, the long filename is
returned.

Related

Setting a file path as text to clipboard in LUA

I am a total noob to LUA.
I need a script that will just copy a file path as text to the clipboard. That's it. I absolutely cannot figure it out. I keep getting the error:
attempt to call a nil value (global 'set_clipboard')
Here is the file path I am trying to copy to the clipboard:
D:_Google Drive_Acting\VO\Room Tone\roomtone.wav
This must be a simple script, right?
For Windows you can do this:
filename = 'my_filename.txt'
io.popen('clip','w'):write(filename):close()
There is no built-in function for that.
In Mac OS, you can do this
function set_clipboard(text)
io.popen('pbcopy','w'):write(text):close()
end
Apparently, in Windows you can use clip instead of pbcopy. I don't know about Linux.

Patched Delphi library for unicode support in TPageProducer callbacks?

I've been using Delphi 2009 with the Indy library (10) that ships and have been upgrading a legacy application that makes heavy use of the TPageProducer. The legacy app was originally written for Delphi 5 / Indy 8.
I'm using the OnHTMLTag property of TPageProducer to specify a function that will handle the HTML transparent tags in my source. My problem was that if I put unicode (Simplified Chinese) characters in the TPageProducer.HTMLDoc property, when the OnHTMLTag callback was called, the TagParams argument contains ?? instead of the expected Chinese characters.
I traced this down to around line 2053 of HTTPApp.pas where we separate out the key / value pairs of the transparent tag:
procedure ExtractHeaderFields(Separators, WhiteSpace: TSysCharSet; Content: PChar;
Strings: TStrings; Decode: Boolean; StripQuotes: Boolean = False);
...
if Decode then
Strings.Add(string(HTTPDecode(AnsiString(DoStripQuotes(ExtractedField)))))
else
Strings.Add(DoStripQuotes(ExtractedField));
...
Everything is fine until we cast the string to an AnsiString and pass it to HTTPDecode, at which point my Strings list contains ?? as does my final TagParams and webpage.
Should there be a version of HTTPDecode that works with Strings instead of AnsiStrings? If so, where might I find this?
For now, I've just disabled the decode routine when I parse my tokens for the TPageProducer, but it isn't a nice fix and would prefer to have a version of this that works with wide characters (if that is even possible).

Any way to guess the mime type on Delphi XE2?

I need to guess the mime type with the purpose of fill the "Content-Type" header for some file uploads.
I fail to found a solution for it.
I wish to call something like: GetMimeType('C:File.jpg') and get back image/jpg.
Best if is multiplataform (for win/osx) but will be enough if only for windows.
Try using the FindMimeFromData Function.
FindMimeFromData contains hard-coded tests for (currently 26) separate
MIME types (see Known MIME Types). This means that if a given buffer
contains data in the format of one of these MIME types, a test exists
in FindMimeFromData that is designed (by scanning through the buffer
contents) to recognize the corresponding MIME type.
from urlmon.pas
function FindMimeFromData(
pBC: IBindCtx; // bind context - can be nil
pwzUrl: LPCWSTR; // url - can be nil
pBuffer: Pointer; // buffer with data to sniff - can be nil (pwzUrl must be valid)
cbSize: DWORD; // size of buffer
pwzMimeProposed: LPCWSTR; // proposed mime if - can be nil
dwMimeFlags: DWORD; // will be defined
out ppwzMimeOut: LPWSTR; // the suggested mime
dwReserved: DWORD // must be 0
): HResult; stdcall;
Also this article to see hot it works MIME Type Detection in Internet Explorer
IE uses GetClassFileOrMime and FindMimeFromData API to detect the mime type of data/files (UrlMon unit in Delphi).
MIME Type Detection in Internet Explorer
The CLSID returned from GetClassFileOrMime could be located in the registry under HKEY_CLASSES_ROOT\CLSID\<clsid>\MimeTypes. (also FileExtensions, FriendlyName).
The registry also holds a MIME database under: HKEY_CLASSES_ROOT\MIME\Database\Content Type.
But since the list of known MIME types is relatively small you could hold that as a resource XML (or whatever) and simply fetch it from there. This will supprt both Windows and OSX.
For file upload operation you can simply always use application/octet-stream.
Indy has TIdMimeTable class (IdGlobal) and it uses a fixed list plus inspecting the registry HKEY_CLASSES_ROOT (see FillMimeTable). If no match is found application/octet-stream is used.
You should probably want to inspect the file content at the server side once the file is uploaded, and not rely on the headers because the ContentType could be tampered at the client side, and also not match with the registry at the server-side.
Internet Direct (Indy) contains a class for this:
class TIdThreadSafeMimeTable
in unit IdCustomHTTPServer
Code example in a HTTP server application:
Response.ContentType :=
Response.HTTPServer.MIMETable.GetFileMIMEType(FileName);
How many file types are you talking about? Maybe you can just create a list of types you want to support.
I can imagine these lists to be available on the internet as well, for instance
here: http://www.webmaster-toolkit.com/mime-types.shtml
here: http://webdesign.about.com/od/multimedia/a/mime-types-by-file-extension.htm
here: List of ALL MimeTypes on the Planet, mapped to File Extensions?
here: http://hul.harvard.edu/ois/systems/wax/wax-public-help/mimetypes.htm
Just get the file extension using ExtractFileExt and check it agains one of those lists. A file doesn't have a mime type in it, so you'll need to use either this list of file extensions, or determine the type by reading the file headers, which is harder and just as unreliable.

KaZip for C++Builder2009/Delphi

I have download and install KaZip2.0 on C++Builder2009 (with little minor changes => only set type String to AnsiString). I have write:
KAZip1->FileName = "test.zip";
KAZip1->CreateZip("test.zip");
KAZip1->Active = true;
KAZip1->Entries->AddFile("pack\\text.txt","xxx.txt");
KAZip1->Active = false;
KAZip1->Close();
now he create a test.zip with included xxx.txt (59byte original, 21byte packed). I open the archiv in WinRAR successful and want open the xxx.txt, but WinRAR says file is corrupt. :(
What is wrong? Can somebody help me?
Extract not working, because file is corrupt?
KAZip1->FileName = "test.zip";
KAZip1->Active = true;
KAZip1->Entries->ExtractToFile("xxx.txt","zzz.txt");
KAZip1->Active = false;
KAZip1->Close();
with little minor changes => only set
type String to AnsiString
Use RawByteString instead of AnsiString.
I have no idea how KaZip2.0 is implemented, but in general, to make a Delphi/C++ library that was designed without Unicode support in mind working properly you need to do two things:
Replace all Char with AnsiChar and all string to AnsiString
Replace all Win API calls with their Ansi variant, i.e. replace AWin32Function with AWin32FunctionA.
In Delphi < 2009, Char = AnsiChar, String = AnsiString, AWin32Function = AWin32FunctionA, but in Delphi >= 2009, by default, Char = WideChar, String = UnicodeString, AWin32Function = AWin32FunctionW.
WinRAR could be simply failing to recognize the header. Try opening it in Windows or some other zip programs.
with little minor changes => only set
type String to AnsiString
That's doesn't work always right, it may compile but it doesn't mean it will work right in D2009 or CB2009, you need to show the places that you convert Strings to AnsiStrings, specially the code deal with : Buffers, Streams and I/O.
It's not surprising that your code is wrong; KaZip has no documentation.
Proper code is:
//Create a new empty zip file
KAZip1->CreateZip("test.zip");
//Open our newly created zip file so we can add files to it
KAZIP1->Open("test.zip");
//Compress text.txt into xxx.txt
KAZip1->Entries->AddFile("pack\\text.txt","xxx.txt");
//Close the file stream
KAZip1->Close();

Opening File paths with spaces in Delphi 5

(Using Delphi 5)
I am attempting to open a log file using the following code:
// The result of this is:
// C:\Program Files\MyProgram\whatever\..\Blah\logs\mylog.log
fileName := ExtractFilePath(Application.ExeName) + '..\Blah\logs\mylog.log';
// The file exists check passes
if (FileExists(fileName)) then
begin
logs := TStringList.Create();
// An exception is thrown here: 'unable to open file'
logs.LoadFromFile(fileName);
end;
If I relocate the log file to C:\mylog.log the code works perfectly. I'm thinking that the spaces in the file path are messing things up. Does anyone know if this is normal behavior for Delphi 5? If it is, is there a function to escape the space or transform the path into a windows 8.3 path?
I'm pretty sure that Delphi 5 handles spaces in filenames ok but it has been a very long time since I have used that specific version. Is the file currently open by another process? It also could be a permissions issue. Can you instead of loading it into a tStringList, try opening it with a tFileStream with the filemode set to "fmOpenRead or fmShareDenyNone".
fStm := tFileStream.Create( filename, fmOpenRead or fmShareDenyNone );
then load your tStringlist from the stream:
Logs.LoadFromStream ( fStm );
Are you sure its not the "..\" thats causing the problem rather than the spaces. Have you tried to see if it works at
c:\My\Path\nospaces\
If so and you are always using the ..\ path, maybe write a simple function to remove the last folder from your application path and create a full correct pathname.
It's odd that Delphi 5 would throw errors about this. I know of an issue with FileExists failing on files with an invalid last-modified-date (since it internally uses FileAge), but it's the opposite here. Instead of using "..\" I would consider risking the current path, and loading from a relative path: LoadFromFile('..\Something\Something.log'); especially for smaller applications, or by calling ExtractFilePath twice: ExtractFilePath(ExtractFilePath(Application.ExeName))
I'm pretty sure Delphi has always handled spaces so I doubt that is the issue.
You don't show the full path. Any chance it is really long? For example I could believe an issue with paths longer than 255 characters.
It's also a bad idea to put log files under Program Files. Often normal users are not given permission to write to anything under Program Files.
Delphi 5 can open files with spaces - that is certainly not the problem. To prove it, try copying it to c:\my log.log- it should open fine.
Is there any more information in the error message you receive? The most likely thing is that someone else (perhaps your own program) is still writing to the log.
The spaces are not a problem. While the '..' could be a problem in Delphi 5, mosts probably the file is locked by the process that writes to it. If you have control of it, make sure it opens the file with fmShareDenyWrite and not fmShareExclusive or fmShareCompat (which is the default).
Also, you can use:
fileName := ExpandFileName(ExtractFilePath(Application.ExeName) + '..\Blah\logs\mylog.log');
to obtain the absolute path from a relative path.
Also, as others have said, it is not good idea to write anything in Program Files. Regular users (that are not Administrators or Power Users) do not have rights to write there (although in Vista is will be virtualized, is is still not a good idea). Use the appropriate Application Data folder for the user (or all users). This folder can be obtained using:
SHGetFolderPath(0,folder,0,SHGFP_TYPE_CURRENT,#path[0])
where folder is either CSIDL_COMMON_APPDATA or CSIDL_LOCAL_APPDATA. See this delphi.about.com article for an example.
Simple :
// if log file = "C:\Program files\mylog.log"
// you'll get :
// »»»»» fileName = 'C:\Program files..\Blah\logs\mylog.log'
// if log file = "C:\mylog.log"
// you'll get :
// »»»»» fileName = 'C:..\Blah\logs\mylog.log'
Try this code instead, I'm pretty sure it will fit your needs :
fileName := IncludeTrailingPathDelimiter(ExtractFilePath(Application.ExeName))
+ '..\Blah\logs\mylog.log';
Regards,
Olivier
Delphi 5 has never had a problem opening files with spaces and I am still using it since it is uber stable and works great for older XP apps. You need to check your code closely.

Resources