How can I add NTFS metadata to any file? - file

Is there a possibility to add information like "Version = 1.2.3.4" to - let's say - a TXT file? Could this be achieved with NTFS metadata? If so, can I set such information by a program?
Thanks in advance for any hint! Bernd

You can use either Alternative Data Stream (ADS), or Extended File Attributes (more e.g. here).
If you are sure your files remain on NTFS, Alternative Data Streams are perfect way how to store any amount of alternative data - but you will lose ADS when such file leaves NTFS.
Another option is to use Extended File Attributes, it's supported cross-platform, cross-FS, but it has limitations (e.g. how much data you can store). If you're going to save just e.g. version information, this is probably the best way to go.

Thank you Robert! I used the Extended File Attributes of NTFS that you proposed. They are called "File Summary Information". Unfortunately the information does not show up for - lets say - a text file in the "Details" tab of the Windows file explorer. I found some tricks for the registry but they didn't work yet. My code is Delphi:
CONST FmtID_SummaryInformation:TGUID= '{F29F85E0-4FF9-1068-AB91-08002B27B3D9}';
// FMTID_DocSummaryInformation:TGUID='{D5CDD502-2E9C-101B-9397-08002B2CF9AE}';
// FMTID_UserDefinedProperties:TGUID='{D5CDD505-2E9C-101B-9397-08002B2CF9AE}';
IID_IPropertySetStorage:TGUID= '{0000013A-0000-0000-C000-000000000046}';
STGFMT_FILE=3; //Indicates that the file must not be a compound file.
//This element is only valid when using the StgCreateStorageEx
//or StgOpenStorageEx functions to access the NTFS file system
//implementation of the IPropertySetStorage interface.
//Therefore, these functions return an error if the riid
//parameter does not specify the IPropertySetStorage interface,
//or if the specified file is not located on an NTFS file system volume.
STGFMT_ANY=4; //Indicates that the system will determine the file type and
//use the appropriate structured storage or property set
//implementation.
//This value cannot be used with the StgCreateStorageEx function.
// Summary Information
PID_TITLE = 2;
PID_SUBJECT = 3;
PID_AUTHOR = 4;
PID_KEYWORDS = 5;
PID_COMMENTS = 6;
PID_TEMPLATE = 7;
PID_LASTAUTHOR = 8;
PID_REVNUMBER = 9;
PID_EDITTIME = 10;
PID_LASTPRINTED = 11;
PID_CREATE_DTM = 12;
PID_LASTSAVE_DTM = 13;
PID_PAGECOUNT = 14;
PID_WORDCOUNT = 15;
PID_CHARCOUNT = 16;
PID_THUMBNAIL = 17;
PID_APPNAME = 18;
PID_SECURITY = 19;
(*
// Document Summary Information
PID_CATEGORY = 2;
PID_PRESFORMAT = 3;
PID_BYTECOUNT = 4;
PID_LINECOUNT = 5;
PID_PARCOUNT = 6;
PID_SLIDECOUNT = 7;
PID_NOTECOUNT = 8;
PID_HIDDENCOUNT = 9;
PID_MMCLIPCOUNT = 10;
PID_SCALE = 11;
PID_HEADINGPAIR = 12;
PID_DOCPARTS = 13;
PID_MANAGER = 14;
PID_COMPANY = 15;
PID_LINKSDIRTY = 16;
PID_CHARCOUNT2 = 17;
*)
FUNCTION IsNTFS(AFileName:AnsiString):Boolean;
VAR fso,drv:OleVariant;
BEGIN
fso:=CreateOleObject('Scripting.FileSystemObject'{=});
drv:=fso.GetDrive(fso.GetDriveName(AFileName));
Result:=drv.FileSystem='NTFS'{=};
END;
FUNCTION StgOpenStorageEx(
CONST pwcsName:POleStr; //Pointer to the path of the
//file containing storage object
grfMode:LongInt; //Specifies the access mode for the object
stgfmt:DWORD; //Specifies the storage file format
grfAttrs:DWORD; //Reserved; must be zero
pStgOptions:Pointer;//Address of STGOPTIONS pointer
reserved2:Pointer; //Reserved; must be zero
riid:PGUID; //Specifies the GUID of the interface pointer
OUT stgOpen:IStorage//Address of an interface pointer
) : HResult; stdcall; external 'ole32.dll'{=};
FUNCTION GetFileSummaryInfo(FileName:AnsiString):AnsiString;
{Read the File Summary Info of a file (NTFS)}
FUNCTION PropertyPIDToCaption(CONST ePID:Cardinal):AnsiString;
BEGIN {PropertyPIDToCaption}
CASE ePID OF
PID_TITLE: Result:='Title';
PID_SUBJECT: Result:='Subject';
PID_AUTHOR: Result:='Author';
PID_KEYWORDS: Result:='Keywords';
PID_COMMENTS: Result:='Comments';
PID_TEMPLATE: Result:='Template';
PID_LASTAUTHOR: Result:='Last Saved By';
PID_REVNUMBER: Result:='Revision Number';
PID_EDITTIME: Result:='Total Editing Time';
PID_LASTPRINTED: Result:='Last Printed';
PID_CREATE_DTM: Result:='Create Time/Date';
PID_LASTSAVE_DTM:Result:='Last Saved Time/Date';
PID_PAGECOUNT: Result:='Number of Pages';
PID_WORDCOUNT: Result:='Number of Words';
PID_CHARCOUNT: Result:='Number of Characters';
PID_THUMBNAIL: Result:='Thumbnail';
PID_APPNAME: Result:='Creating Application';
PID_SECURITY: Result:='Security';
ELSE Result:='$'+IntToHex(ePID,8);
END
END; {PropertyPIDToCaption}
VAR i,k:Integer;
PropSetStg:IPropertySetStorage;
PropSpec:ARRAY OF TPropSpec;
PropStg:IPropertyStorage;
PropVariant:ARRAY OF TPropVariant;
Rslt:HResult;
S:AnsiString;
Stg:IStorage;
PropEnum:IEnumSTATPROPSTG;
HR:HResult;
PropStat:STATPROPSTG;
AHRes:HRESULT;
PFNw,P:PWideChar;
BEGIN {GetFileSummaryInfo}
GetMem(P,257); PFNw:=StringToWideChar(FileName,P,256);
Result := '';
TRY
OleCheck(StgOpenStorageEx(PFNw,STGM_READ OR STGM_SHARE_DENY_WRITE,STGFMT_FILE,0,NIL,NIL,#IID_IPropertySetStorage,Stg));
PropSetStg:=Stg AS IPropertySetStorage;
AHRes:=PropSetStg.Open(FmtID_SummaryInformation,STGM_READ OR STGM_SHARE_EXCLUSIVE,PropStg);
IF AHRes<>S_OK THEN Exit;
OleCheck(AHRes);
OleCheck(PropStg.Enum(PropEnum));
hr:=PropEnum.Next(1,PropStat,NIL);
i:=0;
WHILE hr=S_OK DO BEGIN
inc(i);
SetLength(PropSpec,I);
PropSpec[i-1].ulKind:=PRSPEC_PROPID;
PropSpec[i-1].propid:=PropStat.propid;
hr := PropEnum.Next(1,PropStat, nil);
END;
SetLength(PropVariant,i);
Rslt:=PropStg.ReadMultiple(i,#PropSpec[0],#PropVariant[0]);
IF Rslt=S_FALSE THEN Exit;
FOR k:=0 TO i-1 DO BEGIN
S:='';
IF (PropVariant[k].vt=VT_LPWSTR) AND Assigned(PropVariant[k].pwszVal) THEN
S:=WideCharToString(PropVariant[k].pwszVal);
IF (PropVariant[k].vt=VT_LPSTR) AND Assigned(PropVariant[k].pszVal) THEN
S:=PropVariant[k].pszVal;
S:=PropertyPIDToCaption(PropSpec[k].Propid)+'='+S;
IF S<>'' THEN Result:=Result+S+#13#10;
END;
FINALLY
END;
END; {GetFileSummaryInfo}
PROCEDURE SetFileSummaryInfo(FileName,Author,Title,Subject,Keywords,Comments:AnsiString);
{Write some fields of the File Summary Info of a file (NTFS)}
VAR PropSetStg:IPropertySetStorage;
PropSpec:ARRAY OF TPropSpec;
PropStg:IPropertyStorage;
PropVariant:ARRAY OF TPropVariant;
Stg:IStorage;
PFNw,P:PWideChar;
Anz:LongInt;
BEGIN {SetFileSummaryInfo}
IF NOT IsNTFS(FileName) THEN Exit;
Anz:=5;
GetMem(P,257); PFNw:=StringToWideChar(FileName,P,256);
OleCheck(StgOpenStorageEx(PFNw,STGM_SHARE_EXCLUSIVE OR STGM_READWRITE,STGFMT_ANY,0,NIL,NIL,#IID_IPropertySetStorage,Stg));
PropSetStg:=Stg AS IPropertySetStorage;
OleCheck(PropSetStg.Create(FmtID_SummaryInformation,FmtID_SummaryInformation,PROPSETFLAG_DEFAULT,STGM_CREATE OR STGM_READWRITE OR STGM_SHARE_EXCLUSIVE,PropStg));
Setlength(PropSpec,Anz);
PropSpec[0].ulKind:=PRSPEC_PROPID;
PropSpec[0].propid:=PID_AUTHOR;
PropSpec[1].ulKind:=PRSPEC_PROPID;
PropSpec[1].propid:=PID_TITLE;
PropSpec[2].ulKind:=PRSPEC_PROPID;
PropSpec[2].propid:=PID_SUBJECT;
PropSpec[3].ulKind:=PRSPEC_PROPID;
PropSpec[3].propid:=PID_KEYWORDS;
PropSpec[4].ulKind:=PRSPEC_PROPID;
PropSpec[4].propid:=PID_COMMENTS;
SetLength(PropVariant,Anz);
PropVariant[0].vt:=VT_LPSTR;
PropVariant[0].pszVal:=PChar(Author);
PropVariant[1].vt:=VT_LPSTR;
PropVariant[1].pszVal:=PChar(Title);
PropVariant[2].vt:=VT_LPSTR;
PropVariant[2].pszVal:=PChar(Subject);
PropVariant[3].vt:=VT_LPSTR;
PropVariant[3].pszVal:=PChar(Keywords);
PropVariant[4].vt:=VT_LPSTR;
PropVariant[4].pszVal:=PChar(Comments);
OleCheck(PropStg.WriteMultiple(Anz,#PropSpec[0],#PropVariant[0],2));
PropStg.Commit(STGC_DEFAULT);
FreeMem(P);
END; {SetFileSummaryInfo}

Related

Octave - How can I use pararrayfun with a file in input?

I am a new Octave user. My Octave version is 4.4.1.
I need help on how to use the parallel package.
I have a function modele_file that takes in as input a class structure that contains the path to files. I have to load that 'mat' files (see the code below).
The problem is that octave indicates that my entry is not defined.
I would be grateful if someone can help me find what is missing in my code
files = dir('./../data/*.mat');
[row col] = size(files);
for k = 1:1000
name{k} = getfield(files, {k,1}, 'name');
end
fun_str = #(stg) strcat("./../data/", stg) ;
vec_name = arrayfun(fun_str, name) ;
vec_result = arrayfun(fun_str, repmat({"result/"}, row,1)) ;
a = [vec_name, vec_result'] ;
struct_info = cell2struct(a, {"name", "result"}, 1);
solution = pararrayfun(nproc, modele_file, struct_info)
Here an example of my function :
function modele = modele_file(info_struct)
file = info_struct{1} ;
path = info_struct{2} ;
load(strcat(file)) ;
modele.X = zeros(2,2) ;
save('file.mat', 'modele') ;
Although my function is able to work. My priority is to launch my function, I do not specifically need it to register in an object.
Thank you.

Kafka ByteArray

I'm using Kafka to send produce and consume messages.
Producing is fine, working with a <String, ByteArray> producer.
When consuming, I'm using the code below (taken from an example) but I'm getting each record as being just 8 bytes (sample output beneath code).
Is there a way a consumer can simply take a whole message as a byte array?
Code:
props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
props.put("value.deserializer", "org.apache.kafka.common.serialization.ByteArrayDeserializer");
KafkaConsumer<String, byte[]> consumer = new KafkaConsumer<String, byte[]>(props);
consumer.subscribe(Arrays.asList(topic));
int i = 0;
while (true) {
ConsumerRecords<String, byte[]> records = consumer.poll(100);
for (ConsumerRecord<String, byte[]> record : records)
System.out.printf("offset = %d, key = %s, value = %s\n", record.offset(), record.key(), record.value());
}
Output of System.out :
offset = 1773133, key = 105906453, value = [B#b8eff39
offset = 1773134, key = 105906453, value = [B#7bb1504
offset = 1773135, key = 105906453, value = [B#67b6c728
offset = 1773136, key = 105906453, value = [B#60b1f9c5
offset = 1773137, key = 105906177, value = [B#1cbab5dd
offset = 1773138, key = 105906177, value = [B#4376907b
offset = 1773139, key = 105906177, value = [B#122880ba
offset = 1773140, key = 105906177, value = [B#7db82ceb
offset = 1773141, key = 105906177, value = [B#34657adc
I'm not looking forward to having to assemble a load of these records to re-create a message as I believe I'm missing something and manual assembly may be error prone.
I think you should use
System.out.printf("offset = %d, key = %s, value = %s\n", record.offset(), record.key(), java.util.Arrays.toString(record.value()));
rather than depending on plain array.toString (which gives you garbage instead of actual content). Arrays are probably coming properly, you just debug it wrong way.

How to create a Simulink bus from a typedef struct defined in a C .h file?

Is there a way to create a Simulink bus from the definition of a C struct? Let's say I have some C struct definition in a header file:
typedef struct {
double a, b;
} u_T;
Can I use this to automatically generate a Simulink.Bus object?
Edit: Is there a tool that generates Matlab code for creating Simulink.Bus objects describing the structs from a .h file?
This is supported in the latest version of MATLAB (2017a). Use the following command.
importInfo = Simulink.importExternalCTypes(headerFiles)
For more info see: https://www.mathworks.com/help/simulink/slref/simulink.importexternalctypes.html
You can import a header when creating a bus object, but this is only used for code generation with Simulink Coder, not for normal simulation with Simulink. See the documentation on Simulink.Bus for more details.
The only way to do what you want would be to write a parser that reads your .h file and creates a bus object in the MATLAB workspace. I don't know of any such tool I'm afraid.
Here is a MATLAB script:
filename = 'Test3.h';
fid = fopen(filename);
tline = fgetl(fid);
i = 1;
while ischar(tline)
% Search for structs
if any(strfind(tline,'typedef struct'))
tline = fgetl(fid);
% Get elements
while ~any(strfind(tline,'}'))
% Create Element
el(i) = Simulink.BusElement;
c = regexp(tline,'(\w*) (\w*);','tokens');
% Element Name
el(i).Name = c{1,1}{1,2};
% Element Data type
switch c{1,1}{1,1}
case 'float'
el(i).DataType = 'single';
case 'int8_t'
el(i).DataType = 'int8';
case 'uint32_t'
el(i).DataType = 'uint32';
% Add unknown Data types as cases here
otherwise
el(i).DataType = ['Bus: ',c{1,1}{1,1}];
end
i = i+1;
tline = fgetl(fid);
end
% Get struct name
c = regexp(tline,'} (\w*);', 'tokens');
% Create bus
eval([c{1,1}{1,1},' = Simulink.Bus;']);
% Assign elements
eval([c{1,1}{1,1},'.Elements = el;']);
% Assign Header file
eval([c{1,1}{1,1},'.HeaderFile = ''',filename,''';']);
clear el; i = 1;
end
tline = fgetl(fid);
end
fid = fclose(fid);
clear c fid filename i tline;
I hope it helps...

How can I apply a low-shelving filter using Visualdsp++?

I'm very new to DSP. And have to solve the following problem: applying the low shelving filter for an array of data. The original data is displayed in fract16 (VisualDSP++).
I'm writing something as below but not sure it's correct or not.
Does the following code have any problem with overflow?
If 1 is true, how should I do to prevent it?
Any advice on this problem?
fract16 org_data[256]; //original data
float16 ArrayA[],ArrayB[];
long tmp_A0, tmp_A1, tmp_A2, tmp_B1, tmp_B2;
float filter_paraA[3], filter_paraB[3]; // correctness: 0.xxxxx
// For equalizing
// Low-Shelving filter
for ( i=0; i<2; i++)
{
tmp_A1 = ArrayA[i*2];
tmp_A2 = ArrayA[i*2+1];
tmp_B1 = ArrayB[i*2];
tmp_B2 = ArrayB[i*2+1];
for(j=0;j<256;j++){
tmp_A0 = org_data[j];
org_data[j] = filter_paraA[0] * tmp_A0
+ filter_paraA[1] * tmp_A1
+ filter_paraA[2] * tmp_A2
- filter_paraB[1] * tmp_B1
- filter_paraB[2] * tmp_B2;
tmp_A2 = tmp_A1;
tmp_B2 = tmp_B1;
tmp_A1 = tmp_A0;
tmp_B1 = org_data[j];
}
ArrayA[i*2] = tmp_A1;
ArrayA[i*2+1] = tmp_A2;
ArrayB[i*2] = tmp_B1;
ArrayB[i*2+1] = tmp_B2;
}
I don't know what the range is for fract16, just -1 to +1 approx?
The section that stands out to me as possibly generating an overflow is assigning org_data[j] but will be dependent on what you know about your input signal and your filter coefficients. If you can ensure that multiplying filter_paraA[2:0] to signal with values tmp_A2..1 = [1,1,1] is < max(fract16) you should be fine regardless of the 'B' side.
I would recommend adding some checks for overflow in your code. It doesn't necessarily have to fix it, but you would be able to identify an otherwise very tricky bug. Unless you need absolute max performance I would even leave the check code in place but with less output or setting a flag that gets checked.
macA = filter_paraA[0] * tmp_A0 + filter_paraA[1] * tmp_A1 \
+ filter_paraA[2] * tmp_A2;
macB = filter_paraB[1] * tmp_B1 - filter_paraB[2] * tmp_B2;
if((macA-macB)>1){
printf("ERROR! Overflow detected!\n");
printf("tmp_A[] = [%f, %f, %f]\n",tmp_A2,tmp_A1,tmp_A0);
printf("tmp_B[] = [%f, %f]\n",tmp_B1,tmp_B0);
printf(" i = %i, j = %i\n",i,j);
}

BCB6: How to put elements of a form in an array?

I'm building a simple game in C++Builder6 and I have 42 Image objects on a Form... At start-up I want all Image objects to be disabled, so I wonder can I put all of them in an array and simply loop thorough the entire array and make them Disabled? I know there must be a way, but I'm just new to programming :)
You have several options.
First: You can declare
Image* array[40];
And dynamically construct the image.
for ( int i = 0 ; i < 40; ++i ) {
image[i] = new Image(this); // where "this" is pointer to your form
image[i]->Parent = this;
// option below are optional
image[i]->Height = 50;
image[i]->Width = 50;
image[i]->Left = 40;
image[i]->Top = 100;
image[i]->Tag = i;
image[i]->OnClick = ButtonClick; // connect with method
}
Second option is declare
Image* array[40];
and manually set all values;
array[0] = Image1;
...
array[39] = Image40;
Then you will have all image in array and you can use loop for doing something on all Image

Resources