mirror of https://gitlab.com/nakst/essence
general: use contentType field for file types
This commit is contained in:
parent
4f9b5194cd
commit
910bc1bbb0
|
@ -24,11 +24,9 @@ You can download and test the latest nightly build from https://github.com/nakst
|
||||||
|
|
||||||
These builds are configured to run on emulators only, to make testing easier. Builds for real hardware are coming soon :)
|
These builds are configured to run on emulators only, to make testing easier. Builds for real hardware are coming soon :)
|
||||||
|
|
||||||
## Source
|
## Building
|
||||||
|
|
||||||
See `help/Building.md` for a description of how to build and test the system from source.
|
See `help/Building.md` for a description of how to build and test the system.
|
||||||
|
|
||||||
For an overview of the files in the source tree, see `help/Source Map.md`.
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
|
|
|
@ -13,108 +13,131 @@ background_service=1
|
||||||
source=apps/file_manager/main.cpp
|
source=apps/file_manager/main.cpp
|
||||||
|
|
||||||
[file_type]
|
[file_type]
|
||||||
extension=esx
|
match=ext:esx
|
||||||
name=Executable
|
name=Executable
|
||||||
icon=icon_application_default_icon
|
icon=icon_application_default_icon
|
||||||
|
uuid=BF-88-E4-DD-71-E8-5F-DE-16-C5-AF-33-41-C7-A2-96
|
||||||
|
|
||||||
[file_type]
|
[file_type]
|
||||||
extension=ini
|
match=ext:ini
|
||||||
name=Configuration file
|
name=Configuration file
|
||||||
icon=icon_application_x_desktop
|
icon=icon_application_x_desktop
|
||||||
|
uuid=81-72-43-29-E5-37-89-51-8E-22-A0-67-A5-B9-42-2C
|
||||||
|
textual=1
|
||||||
|
|
||||||
[file_type]
|
[file_type]
|
||||||
extension=esx_symbols
|
match=ext:png
|
||||||
name=Debugging data
|
|
||||||
icon=icon_extension
|
|
||||||
|
|
||||||
[file_type]
|
|
||||||
extension=exe
|
|
||||||
name=PC executable
|
|
||||||
icon=icon_application_x_ms_dos_executable
|
|
||||||
|
|
||||||
[file_type]
|
|
||||||
extension=png
|
|
||||||
name=PNG image
|
name=PNG image
|
||||||
icon=icon_image_x_generic
|
icon=icon_image_x_generic
|
||||||
has_thumbnail_generator=1
|
has_thumbnail_generator=1
|
||||||
|
uuid=59-21-05-4D-34-40-AB-61-EC-F9-7D-5C-6E-04-96-AE
|
||||||
|
|
||||||
[file_type]
|
[file_type]
|
||||||
extension=jpg
|
match=ext:jpg,ext:jpeg
|
||||||
name=JPG image
|
name=JPG image
|
||||||
icon=icon_image_x_generic
|
icon=icon_image_x_generic
|
||||||
has_thumbnail_generator=1
|
has_thumbnail_generator=1
|
||||||
|
uuid=D8-C2-13-B0-53-64-82-11-48-7B-5B-64-0F-92-B9-38
|
||||||
|
|
||||||
[file_type]
|
[file_type]
|
||||||
extension=ttf
|
match=ext:tga
|
||||||
|
name=TGA image
|
||||||
|
icon=icon_image_x_generic
|
||||||
|
has_thumbnail_generator=1
|
||||||
|
uuid=69-62-4E-28-A1-E1-7B-35-64-2E-36-01-65-91-BE-A1
|
||||||
|
|
||||||
|
[file_type]
|
||||||
|
match=ext:bmp
|
||||||
|
name=BMP image
|
||||||
|
icon=icon_image_x_generic
|
||||||
|
has_thumbnail_generator=1
|
||||||
|
uuid=40-15-B7-82-99-6D-D5-41-96-D5-3B-6D-A6-5F-07-34
|
||||||
|
|
||||||
|
[file_type]
|
||||||
|
match=ext:ttf
|
||||||
name=TrueType font
|
name=TrueType font
|
||||||
icon=icon_font_x_generic
|
icon=icon_font_x_generic
|
||||||
|
uuid=DA-BF-EC-06-31-8A-67-B6-E3-95-BC-D1-92-D2-9A-56
|
||||||
|
|
||||||
[file_type]
|
[file_type]
|
||||||
extension=otf
|
match=ext:otf
|
||||||
name=OpenType font
|
name=OpenType font
|
||||||
icon=icon_font_x_generic
|
icon=icon_font_x_generic
|
||||||
|
uuid=E7-2B-BB-E7-FF-75-32-E0-4E-75-41-C0-D2-ED-80-56
|
||||||
|
|
||||||
[file_type]
|
[file_type]
|
||||||
extension=a
|
match=ext:a
|
||||||
name=Static library
|
name=Static library
|
||||||
icon=icon_extension
|
icon=icon_extension
|
||||||
|
uuid=7D-39-BF-18-9E-07-BC-D3-4F-9F-87-EC-6F-70-65-5D
|
||||||
|
|
||||||
[file_type]
|
[file_type]
|
||||||
extension=dat
|
match=ext:dat
|
||||||
name=Database
|
name=Application data
|
||||||
icon=icon_office_database
|
icon=icon_office_database
|
||||||
|
uuid=B5-32-22-14-01-CB-D0-1D-A2-55-08-C7-0D-46-86-53
|
||||||
|
|
||||||
[file_type]
|
[file_type]
|
||||||
extension=icon_pack
|
match=ext:ekm
|
||||||
name=Icon pack
|
|
||||||
icon=icon_package_x_generic
|
|
||||||
|
|
||||||
[file_type]
|
|
||||||
extension=ekm
|
|
||||||
name=Kernel module
|
name=Kernel module
|
||||||
icon=icon_extension
|
icon=icon_extension
|
||||||
|
uuid=80-6D-8E-D6-C7-45-AD-A7-03-5B-B3-64-C5-0A-EE-C6
|
||||||
|
|
||||||
[file_type]
|
[file_type]
|
||||||
extension=o
|
match=ext:o
|
||||||
name=Binary object
|
name=Binary object
|
||||||
icon=icon_extension
|
icon=icon_extension
|
||||||
|
uuid=B5-19-F2-0D-AD-4F-D4-C9-A4-BF-97-E4-5E-4C-55-00
|
||||||
|
|
||||||
[file_type]
|
[file_type]
|
||||||
extension=c
|
match=ext:c
|
||||||
name=C source
|
name=C source
|
||||||
icon=icon_text_x_csrc
|
icon=icon_text_x_csrc
|
||||||
|
uuid=36-02-D3-AC-6C-DE-8D-31-FA-70-B2-DA-FA-81-53-69
|
||||||
|
textual=1
|
||||||
|
|
||||||
[file_type]
|
[file_type]
|
||||||
extension=cpp
|
match=ext:cpp
|
||||||
name=C++ source
|
name=C++ source
|
||||||
icon=icon_text_x_csrc
|
icon=icon_text_x_csrc
|
||||||
|
uuid=35-84-A6-0E-52-28-BA-AB-CA-74-14-F4-E1-15-CA-5F
|
||||||
|
textual=1
|
||||||
|
|
||||||
[file_type]
|
[file_type]
|
||||||
extension=h
|
match=ext:h
|
||||||
name=C header
|
name=C header
|
||||||
icon=icon_text_x_csrc
|
icon=icon_text_x_csrc
|
||||||
|
uuid=D1-16-C4-C1-7B-C0-ED-4F-CA-AC-18-05-32-1D-56-32
|
||||||
|
textual=1
|
||||||
|
|
||||||
[file_type]
|
[file_type]
|
||||||
extension=txt
|
match=ext:txt
|
||||||
name=Text file
|
name=Text file
|
||||||
icon=icon_text
|
icon=icon_text
|
||||||
|
uuid=25-65-4C-89-E7-29-EA-9E-B5-BE-B5-CA-A7-60-BD-3D
|
||||||
|
textual=1
|
||||||
|
|
||||||
[file_type]
|
[file_type]
|
||||||
extension=md
|
match=ext:md
|
||||||
name=Markdown file
|
name=Markdown file
|
||||||
icon=icon_text_markdown
|
icon=icon_text_markdown
|
||||||
|
uuid=B1-C3-9E-56-C9-B0-85-D6-AF-98-12-1C-2E-29-8D-24
|
||||||
|
textual=1
|
||||||
|
|
||||||
[file_type]
|
[file_type]
|
||||||
extension=ogg
|
match=ext:ogg
|
||||||
name=OGG audio
|
name=OGG audio
|
||||||
icon=icon_audio_x_generic
|
icon=icon_audio_x_generic
|
||||||
|
uuid=E5-14-14-ED-4D-67-C0-D0-62-A1-A4-D4-F5-82-A7-88
|
||||||
|
|
||||||
[file_type]
|
[file_type]
|
||||||
extension=mp4
|
match=ext:mp4
|
||||||
name=MP4 video
|
name=MP4 video
|
||||||
icon=icon_view_list_video_symbolic
|
icon=icon_view_list_video_symbolic
|
||||||
|
uuid=02-76-E1-41-B8-54-19-A9-05-8D-C1-3F-6E-8F-D7-9E
|
||||||
|
|
||||||
[file_type]
|
[file_type]
|
||||||
extension=wav
|
match=ext:wav
|
||||||
name=Wave audio
|
name=Wave audio
|
||||||
icon=icon_audio_x_generic
|
icon=icon_audio_x_generic
|
||||||
|
uuid=87-BC-A1-A1-25-76-26-5C-8F-94-D6-D8-35-B6-7A-9F
|
||||||
|
|
|
@ -22,10 +22,11 @@ void CommandRename(Instance *instance, EsElement *, EsCommand *) {
|
||||||
instance->rename.index = index;
|
instance->rename.index = index;
|
||||||
|
|
||||||
FolderEntry *entry = instance->listContents[index].entry;
|
FolderEntry *entry = instance->listContents[index].entry;
|
||||||
|
ptrdiff_t extensionOffset = PathGetExtension(entry->GetName()).text - entry->name;
|
||||||
|
|
||||||
if (entry->extensionOffset != entry->nameBytes) {
|
if (extensionOffset != entry->nameBytes) {
|
||||||
// Don't include the file extension in the initial selection.
|
// Don't include the file extension in the initial selection.
|
||||||
EsTextboxSetSelection(instance->rename.textbox, 0, 0, 0, entry->extensionOffset - 1);
|
EsTextboxSetSelection(instance->rename.textbox, 0, 0, 0, extensionOffset - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
instance->rename.textbox->messageUser = [] (EsElement *element, EsMessage *message) {
|
instance->rename.textbox->messageUser = [] (EsElement *element, EsMessage *message) {
|
||||||
|
@ -499,23 +500,32 @@ void InstanceRegisterCommands(Instance *instance) {
|
||||||
EsCommandRegister(&instance->commandRename, instance, INTERFACE_STRING(FileManagerRenameAction), CommandRename, stableCommandID++, "F2");
|
EsCommandRegister(&instance->commandRename, instance, INTERFACE_STRING(FileManagerRenameAction), CommandRename, stableCommandID++, "F2");
|
||||||
|
|
||||||
EsCommandRegister(&instance->commandViewDetails, instance, INTERFACE_STRING(CommonListViewTypeDetails), [] (Instance *instance, EsElement *, EsCommand *) {
|
EsCommandRegister(&instance->commandViewDetails, instance, INTERFACE_STRING(CommonListViewTypeDetails), [] (Instance *instance, EsElement *, EsCommand *) {
|
||||||
uint8_t old = instance->viewSettings.viewType;
|
if (instance->viewSettings.viewType != VIEW_DETAILS) {
|
||||||
|
EsElementStartTransition(instance->list, ES_TRANSITION_FADE, ES_ELEMENT_TRANSITION_CONTENT_ONLY, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
instance->viewSettings.viewType = VIEW_DETAILS;
|
instance->viewSettings.viewType = VIEW_DETAILS;
|
||||||
InstanceRefreshViewType(instance, old != instance->viewSettings.viewType);
|
InstanceRefreshViewType(instance);
|
||||||
InstanceViewSettingsUpdated(instance);
|
InstanceViewSettingsUpdated(instance);
|
||||||
}, stableCommandID++);
|
}, stableCommandID++);
|
||||||
|
|
||||||
EsCommandRegister(&instance->commandViewTiles, instance, INTERFACE_STRING(CommonListViewTypeTiles), [] (Instance *instance, EsElement *, EsCommand *) {
|
EsCommandRegister(&instance->commandViewTiles, instance, INTERFACE_STRING(CommonListViewTypeTiles), [] (Instance *instance, EsElement *, EsCommand *) {
|
||||||
uint8_t old = instance->viewSettings.viewType;
|
if (instance->viewSettings.viewType != VIEW_TILES) {
|
||||||
|
EsElementStartTransition(instance->list, ES_TRANSITION_FADE, ES_ELEMENT_TRANSITION_CONTENT_ONLY, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
instance->viewSettings.viewType = VIEW_TILES;
|
instance->viewSettings.viewType = VIEW_TILES;
|
||||||
InstanceRefreshViewType(instance, old != instance->viewSettings.viewType);
|
InstanceRefreshViewType(instance);
|
||||||
InstanceViewSettingsUpdated(instance);
|
InstanceViewSettingsUpdated(instance);
|
||||||
}, stableCommandID++);
|
}, stableCommandID++);
|
||||||
|
|
||||||
EsCommandRegister(&instance->commandViewThumbnails, instance, INTERFACE_STRING(CommonListViewTypeThumbnails), [] (Instance *instance, EsElement *, EsCommand *) {
|
EsCommandRegister(&instance->commandViewThumbnails, instance, INTERFACE_STRING(CommonListViewTypeThumbnails), [] (Instance *instance, EsElement *, EsCommand *) {
|
||||||
uint8_t old = instance->viewSettings.viewType;
|
if (instance->viewSettings.viewType != VIEW_THUMBNAILS) {
|
||||||
|
EsElementStartTransition(instance->list, ES_TRANSITION_FADE, ES_ELEMENT_TRANSITION_CONTENT_ONLY, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
instance->viewSettings.viewType = VIEW_THUMBNAILS;
|
instance->viewSettings.viewType = VIEW_THUMBNAILS;
|
||||||
InstanceRefreshViewType(instance, old != instance->viewSettings.viewType);
|
InstanceRefreshViewType(instance);
|
||||||
InstanceViewSettingsUpdated(instance);
|
InstanceViewSettingsUpdated(instance);
|
||||||
}, stableCommandID++);
|
}, stableCommandID++);
|
||||||
|
|
||||||
|
|
|
@ -394,7 +394,6 @@ FolderEntry *FolderAddEntry(Folder *folder, const char *_name, size_t nameBytes,
|
||||||
entry->handles = 1;
|
entry->handles = 1;
|
||||||
entry->name = name;
|
entry->name = name;
|
||||||
entry->nameBytes = nameBytes;
|
entry->nameBytes = nameBytes;
|
||||||
entry->extensionOffset = PathGetExtension(entry->GetName()).text - name;
|
|
||||||
entry->internalName = name;
|
entry->internalName = name;
|
||||||
entry->internalNameBytes = nameBytes;
|
entry->internalNameBytes = nameBytes;
|
||||||
|
|
||||||
|
@ -417,6 +416,7 @@ FolderEntry *FolderAddEntry(Folder *folder, const char *_name, size_t nameBytes,
|
||||||
entry->size = information->fileSize;
|
entry->size = information->fileSize;
|
||||||
entry->isFolder = information->type == ES_NODE_DIRECTORY;
|
entry->isFolder = information->type == ES_NODE_DIRECTORY;
|
||||||
entry->sizeUnknown = entry->isFolder && information->directoryChildren == ES_DIRECTORY_CHILDREN_UNKNOWN;
|
entry->sizeUnknown = entry->isFolder && information->directoryChildren == ES_DIRECTORY_CHILDREN_UNKNOWN;
|
||||||
|
entry->contentType = information->contentType;
|
||||||
|
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
@ -459,12 +459,26 @@ uint64_t FolderRemoveEntryAndUpdateInstances(Folder *folder, const char *name, s
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FolderFileUpdatedAtPath(String path, Instance *instance) {
|
void FolderFileUpdatedAtPath(String path, Instance *instance, bool setGuessedContentType = false) {
|
||||||
path = PathRemoveTrailingSlash(path);
|
path = PathRemoveTrailingSlash(path);
|
||||||
String file = PathGetName(path);
|
String file = PathGetName(path);
|
||||||
String folder = PathGetParent(path);
|
String folder = PathGetParent(path);
|
||||||
EsDirectoryChild information = {};
|
EsDirectoryChild information = {};
|
||||||
bool add = ES_SUCCESS == EsPathQueryInformation(STRING(path), &information);
|
bool add = ES_SUCCESS == EsPathQueryInformation(STRING(path), &information);
|
||||||
|
EsUniqueIdentifier zeroIdentifier = {};
|
||||||
|
|
||||||
|
if (setGuessedContentType && 0 == EsMemoryCompare(&information.contentType, &zeroIdentifier, sizeof(EsUniqueIdentifier))) {
|
||||||
|
EsUniqueIdentifier identifier = FileTypeMatchByExtension(path);
|
||||||
|
|
||||||
|
if (EsMemoryCompare(&identifier, &zeroIdentifier, sizeof(EsUniqueIdentifier))) {
|
||||||
|
EsFileInformation information = EsFileOpen(STRING(path), ES_FILE_WRITE_SHARED | ES_NODE_FAIL_IF_NOT_FOUND);
|
||||||
|
|
||||||
|
if (information.error == ES_SUCCESS) {
|
||||||
|
EsFileControl(information.handle, ES_FILE_CONTROL_SET_CONTENT_TYPE, &identifier, sizeof(identifier));
|
||||||
|
EsHandleClose(information.handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (uintptr_t i = 0; i < loadedFolders.Length(); i++) {
|
for (uintptr_t i = 0; i < loadedFolders.Length(); i++) {
|
||||||
if (loadedFolders[i]->itemHandler->type != NAMESPACE_HANDLER_FILE_SYSTEM) continue;
|
if (loadedFolders[i]->itemHandler->type != NAMESPACE_HANDLER_FILE_SYSTEM) continue;
|
||||||
|
|
|
@ -53,12 +53,14 @@ const char *errorTypeStrings[] = {
|
||||||
#define LOAD_FOLDER_NO_FOCUS (1 << 8)
|
#define LOAD_FOLDER_NO_FOCUS (1 << 8)
|
||||||
|
|
||||||
struct FolderEntry {
|
struct FolderEntry {
|
||||||
|
// TODO Can this structure be made smaller?
|
||||||
uint16_t handles;
|
uint16_t handles;
|
||||||
bool isFolder, sizeUnknown;
|
bool isFolder, sizeUnknown, guessedContentType;
|
||||||
uint8_t nameBytes, extensionOffset, internalNameBytes; // 0 -> 256.
|
uint8_t nameBytes, internalNameBytes; // 0 -> 256.
|
||||||
char *name, *internalName;
|
char *name, *internalName;
|
||||||
EsFileOffset size, previousSize;
|
EsFileOffset size, previousSize;
|
||||||
uint64_t id;
|
uint64_t id;
|
||||||
|
EsUniqueIdentifier contentType;
|
||||||
|
|
||||||
inline String GetName() {
|
inline String GetName() {
|
||||||
return { .text = name, .bytes = nameBytes ?: 256u, .allocated = nameBytes ?: 256u };
|
return { .text = name, .bytes = nameBytes ?: 256u, .allocated = nameBytes ?: 256u };
|
||||||
|
@ -67,11 +69,6 @@ struct FolderEntry {
|
||||||
inline String GetInternalName() {
|
inline String GetInternalName() {
|
||||||
return { .text = internalName, .bytes = internalNameBytes ?: 256u, .allocated = internalNameBytes ?: 256u };
|
return { .text = internalName, .bytes = internalNameBytes ?: 256u, .allocated = internalNameBytes ?: 256u };
|
||||||
}
|
}
|
||||||
|
|
||||||
inline String GetExtension() {
|
|
||||||
uintptr_t offset = extensionOffset ?: 256u;
|
|
||||||
return { .text = name + offset, .bytes = (nameBytes ?: 256u) - offset };
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ListEntry {
|
struct ListEntry {
|
||||||
|
@ -227,7 +224,7 @@ void InstanceReportError(struct Instance *instance, int error, EsError code);
|
||||||
bool InstanceLoadFolder(Instance *instance, String path /* takes ownership */, int historyMode = 0);
|
bool InstanceLoadFolder(Instance *instance, String path /* takes ownership */, int historyMode = 0);
|
||||||
void InstanceUpdateStatusString(Instance *instance);
|
void InstanceUpdateStatusString(Instance *instance);
|
||||||
void InstanceViewSettingsUpdated(Instance *instance);
|
void InstanceViewSettingsUpdated(Instance *instance);
|
||||||
void InstanceRefreshViewType(Instance *instance, bool startTransition);
|
void InstanceRefreshViewType(Instance *instance);
|
||||||
void InstanceFolderPathChanged(Instance *instance, bool fromLoadFolder);
|
void InstanceFolderPathChanged(Instance *instance, bool fromLoadFolder);
|
||||||
void InstanceAddContents(struct Instance *instance, HashTable *newEntries);
|
void InstanceAddContents(struct Instance *instance, HashTable *newEntries);
|
||||||
void InstanceAddSingle(struct Instance *instance, ListEntry newEntry);
|
void InstanceAddSingle(struct Instance *instance, ListEntry newEntry);
|
||||||
|
@ -583,6 +580,10 @@ void _start() {
|
||||||
StringDestroy(&openDocuments[i]);
|
StringDestroy(&openDocuments[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (uintptr_t i = 0; i < knownFileTypes.Length(); i++) {
|
||||||
|
knownFileTypes[i].applicationEntries.Free();
|
||||||
|
}
|
||||||
|
|
||||||
EsAssert(!instances.Length());
|
EsAssert(!instances.Length());
|
||||||
EsHeapFree(fileTypesBuffer.out);
|
EsHeapFree(fileTypesBuffer.out);
|
||||||
|
|
||||||
|
@ -608,7 +609,7 @@ void _start() {
|
||||||
size_t pathSectionCount = PathCountSections(fullPath);
|
size_t pathSectionCount = PathCountSections(fullPath);
|
||||||
|
|
||||||
for (uintptr_t i = 0; i < pathSectionCount; i++) {
|
for (uintptr_t i = 0; i < pathSectionCount; i++) {
|
||||||
FolderFileUpdatedAtPath(PathGetParent(fullPath, i + 1), nullptr);
|
FolderFileUpdatedAtPath(PathGetParent(fullPath, i + 1), nullptr, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
EsHandleClose(message->user.context1.u);
|
EsHandleClose(message->user.context1.u);
|
||||||
|
|
|
@ -2,101 +2,242 @@
|
||||||
// It is released under the terms of the MIT license -- see LICENSE.md.
|
// It is released under the terms of the MIT license -- see LICENSE.md.
|
||||||
// Written by: nakst.
|
// Written by: nakst.
|
||||||
|
|
||||||
|
struct FileTypeApplicationEntry {
|
||||||
|
int64_t application;
|
||||||
|
bool open;
|
||||||
|
};
|
||||||
|
|
||||||
struct FileType {
|
struct FileType {
|
||||||
|
Array<FileTypeApplicationEntry> applicationEntries; // One per application that is involved with this type.
|
||||||
|
EsUniqueIdentifier identifier;
|
||||||
char *name;
|
char *name;
|
||||||
size_t nameBytes;
|
size_t nameBytes;
|
||||||
char *extension;
|
|
||||||
size_t extensionBytes;
|
|
||||||
uint32_t iconID;
|
uint32_t iconID;
|
||||||
int64_t openHandler;
|
bool textual;
|
||||||
|
bool hasThumbnailGenerator; // TODO Allow applications to register their own thumbnail generators.
|
||||||
// TODO Allow applications to register their own thumbnail generators.
|
|
||||||
bool hasThumbnailGenerator;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Array<FileType> knownFileTypes;
|
Array<FileType> knownFileTypes;
|
||||||
HashStore<char, uintptr_t /* index into knownFileTypes */> knownFileTypesByExtension;
|
HashStore<char, EsUniqueIdentifier> knownFileTypesByExtension;
|
||||||
EsBuffer fileTypesBuffer;
|
EsBuffer fileTypesBuffer;
|
||||||
|
|
||||||
void AddKnownFileTypes() {
|
void AddKnownFileTypes() {
|
||||||
#define ADD_FILE_TYPE(_extension, _name, _iconID) \
|
#define ADD_FILE_TYPE(_name, _iconID) \
|
||||||
{ \
|
{ \
|
||||||
FileType type = {}; \
|
FileType type = {}; \
|
||||||
type.name = (char *) _name; \
|
type.name = (char *) _name; \
|
||||||
type.nameBytes = EsCStringLength(_name); \
|
type.nameBytes = EsCStringLength(_name); \
|
||||||
type.extension = (char *) _extension; \
|
|
||||||
type.extensionBytes = EsCStringLength(_extension); \
|
|
||||||
type.iconID = _iconID; \
|
type.iconID = _iconID; \
|
||||||
knownFileTypes.Add(type); \
|
knownFileTypes.Add(type); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define KNOWN_FILE_TYPE_DIRECTORY (0)
|
#define KNOWN_FILE_TYPE_DIRECTORY (0)
|
||||||
ADD_FILE_TYPE("", interfaceString_CommonItemFolder, ES_ICON_FOLDER);
|
ADD_FILE_TYPE(interfaceString_CommonItemFolder, ES_ICON_FOLDER);
|
||||||
#define KNOWN_FILE_TYPE_UNKNOWN (1)
|
#define KNOWN_FILE_TYPE_UNKNOWN (1)
|
||||||
ADD_FILE_TYPE("", interfaceString_CommonItemFile, ES_ICON_UNKNOWN);
|
ADD_FILE_TYPE(interfaceString_CommonItemFile, ES_ICON_UNKNOWN);
|
||||||
#define KNOWN_FILE_TYPE_DRIVE_HDD (2)
|
#define KNOWN_FILE_TYPE_DRIVE_HDD (2)
|
||||||
ADD_FILE_TYPE("", interfaceString_CommonDriveHDD, ES_ICON_DRIVE_HARDDISK);
|
ADD_FILE_TYPE(interfaceString_CommonDriveHDD, ES_ICON_DRIVE_HARDDISK);
|
||||||
#define KNOWN_FILE_TYPE_DRIVE_SSD (3)
|
#define KNOWN_FILE_TYPE_DRIVE_SSD (3)
|
||||||
ADD_FILE_TYPE("", interfaceString_CommonDriveSSD, ES_ICON_DRIVE_HARDDISK_SOLIDSTATE);
|
ADD_FILE_TYPE(interfaceString_CommonDriveSSD, ES_ICON_DRIVE_HARDDISK_SOLIDSTATE);
|
||||||
#define KNOWN_FILE_TYPE_DRIVE_CDROM (4)
|
#define KNOWN_FILE_TYPE_DRIVE_CDROM (4)
|
||||||
ADD_FILE_TYPE("", interfaceString_CommonDriveCDROM, ES_ICON_MEDIA_OPTICAL);
|
ADD_FILE_TYPE(interfaceString_CommonDriveCDROM, ES_ICON_MEDIA_OPTICAL);
|
||||||
#define KNOWN_FILE_TYPE_DRIVE_USB_MASS_STORAGE (5)
|
#define KNOWN_FILE_TYPE_DRIVE_USB_MASS_STORAGE (5)
|
||||||
ADD_FILE_TYPE("", interfaceString_CommonDriveUSBMassStorage, ES_ICON_DRIVE_REMOVABLE_MEDIA_USB);
|
ADD_FILE_TYPE(interfaceString_CommonDriveUSBMassStorage, ES_ICON_DRIVE_REMOVABLE_MEDIA_USB);
|
||||||
#define KNOWN_FILE_TYPE_DRIVES_PAGE (6)
|
#define KNOWN_FILE_TYPE_DRIVES_PAGE (6)
|
||||||
ADD_FILE_TYPE("", interfaceString_FileManagerDrivesPage, ES_ICON_COMPUTER_LAPTOP);
|
ADD_FILE_TYPE(interfaceString_FileManagerDrivesPage, ES_ICON_COMPUTER_LAPTOP);
|
||||||
|
#define KNOWN_FILE_TYPE_SPECIAL_COUNT (7)
|
||||||
|
|
||||||
fileTypesBuffer = { .canGrow = true };
|
fileTypesBuffer = { .canGrow = true };
|
||||||
EsSystemConfigurationReadFileTypes(&fileTypesBuffer);
|
EsSystemConfigurationReadFileTypes(&fileTypesBuffer);
|
||||||
|
|
||||||
EsINIState s = { .buffer = (char *) fileTypesBuffer.out, .bytes = fileTypesBuffer.bytes };
|
EsINIState s = { .buffer = (char *) fileTypesBuffer.out, .bytes = fileTypesBuffer.bytes };
|
||||||
FileType type = {};
|
FileType type = {};
|
||||||
|
FileTypeApplicationEntry applicationEntry = {};
|
||||||
|
bool specifiedTextual = false, specifiedHasThumbnailGenerator = false, hasUUID = false;
|
||||||
|
const char *matchValue;
|
||||||
|
size_t matchValueBytes = 0;
|
||||||
|
|
||||||
while (EsINIParse(&s)) {
|
while (EsINIParse(&s)) {
|
||||||
if (0 == EsStringCompareRaw(s.key, s.keyBytes, EsLiteral("name"))) {
|
if (0 == EsStringCompareRaw(s.key, s.keyBytes, EsLiteral("name"))) {
|
||||||
type.name = s.value, type.nameBytes = s.valueBytes;
|
type.name = s.value, type.nameBytes = s.valueBytes;
|
||||||
} else if (0 == EsStringCompareRaw(s.key, s.keyBytes, EsLiteral("extension"))) {
|
} else if (0 == EsStringCompareRaw(s.key, s.keyBytes, EsLiteral("uuid"))) {
|
||||||
type.extension = s.value, type.extensionBytes = s.valueBytes;
|
type.identifier = EsUniqueIdentifierParse(s.value, s.valueBytes);
|
||||||
} else if (0 == EsStringCompareRaw(s.key, s.keyBytes, EsLiteral("open"))) {
|
hasUUID = true;
|
||||||
type.openHandler = EsIntegerParse(s.value, s.valueBytes);
|
|
||||||
} else if (0 == EsStringCompareRaw(s.key, s.keyBytes, EsLiteral("icon"))) {
|
} else if (0 == EsStringCompareRaw(s.key, s.keyBytes, EsLiteral("icon"))) {
|
||||||
type.iconID = EsIconIDFromString(s.value, s.valueBytes);
|
type.iconID = EsIconIDFromString(s.value, s.valueBytes);
|
||||||
} else if (0 == EsStringCompareRaw(s.key, s.keyBytes, EsLiteral("has_thumbnail_generator")) && EsIntegerParse(s.value, s.valueBytes)) {
|
} else if (0 == EsStringCompareRaw(s.key, s.keyBytes, EsLiteral("has_thumbnail_generator"))) {
|
||||||
// TODO Proper thumbnail generator registrations.
|
// TODO Proper thumbnail generator registrations.
|
||||||
type.hasThumbnailGenerator = true;
|
type.hasThumbnailGenerator = EsIntegerParse(s.value, s.valueBytes) != 0;
|
||||||
|
} else if (0 == EsStringCompareRaw(s.key, s.keyBytes, EsLiteral("textual"))) {
|
||||||
|
type.textual = EsIntegerParse(s.value, s.valueBytes) != 0;
|
||||||
|
} else if (0 == EsStringCompareRaw(s.key, s.keyBytes, EsLiteral("application"))) {
|
||||||
|
applicationEntry.application = EsIntegerParse(s.value, s.valueBytes);
|
||||||
|
} else if (0 == EsStringCompareRaw(s.key, s.keyBytes, EsLiteral("actions"))) {
|
||||||
|
uintptr_t p = 0, q = 0;
|
||||||
|
|
||||||
|
while (q <= s.valueBytes) {
|
||||||
|
if (q == s.valueBytes || s.value[q] == ',') {
|
||||||
|
String string = StringFromLiteralWithSize(&s.value[p], q - p);
|
||||||
|
p = q + 1;
|
||||||
|
|
||||||
|
if (StringEquals(string, StringFromLiteral("open"))) {
|
||||||
|
applicationEntry.open = true;
|
||||||
|
} else {
|
||||||
|
EsPrint("File Manager: Unknown file type entry action '%s'.\n", STRFMT(string));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
q++;
|
||||||
|
}
|
||||||
|
} else if (0 == EsStringCompareRaw(s.key, s.keyBytes, EsLiteral("match"))) {
|
||||||
|
matchValue = s.value;
|
||||||
|
matchValueBytes = s.valueBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!EsINIPeek(&s) || !s.keyBytes) {
|
if (!EsINIPeek(&s) || !s.keyBytes) {
|
||||||
uintptr_t index = knownFileTypes.Length();
|
EsUniqueIdentifier zeroIdentifier = {};
|
||||||
knownFileTypes.Add(type);
|
|
||||||
*knownFileTypesByExtension.Put(type.extension, type.extensionBytes) = index;
|
if (EsMemoryCompare(&type.identifier, &zeroIdentifier, sizeof(EsUniqueIdentifier))) {
|
||||||
|
bool typeFound = false;
|
||||||
|
uint32_t typeIndex = 0;
|
||||||
|
|
||||||
|
ES_MACRO_SEARCH(knownFileTypes.Length(), {
|
||||||
|
result = EsMemoryCompare(&type.identifier, &knownFileTypes[index].identifier, sizeof(EsUniqueIdentifier));
|
||||||
|
}, typeIndex, typeFound);
|
||||||
|
|
||||||
|
EsAssert(typeIndex >= KNOWN_FILE_TYPE_SPECIAL_COUNT);
|
||||||
|
FileType *existing;
|
||||||
|
|
||||||
|
if (!typeFound) {
|
||||||
|
existing = knownFileTypes.Insert(type, typeIndex);
|
||||||
|
EsPrint("File Manager: Type %I registered by application %d with name '%s'.\n",
|
||||||
|
type.identifier, applicationEntry.application, type.nameBytes, type.name);
|
||||||
|
} else {
|
||||||
|
// TODO Priority system.
|
||||||
|
existing = &knownFileTypes[typeIndex];
|
||||||
|
EsAssert(0 == EsMemoryCompare(&existing->identifier, &type.identifier, sizeof(EsUniqueIdentifier)));
|
||||||
|
if (type.nameBytes) existing->name = type.name, existing->nameBytes = type.nameBytes;
|
||||||
|
if (type.iconID) existing->iconID = type.iconID;
|
||||||
|
if (specifiedTextual) existing->textual = type.textual;
|
||||||
|
if (specifiedHasThumbnailGenerator) existing->hasThumbnailGenerator = type.hasThumbnailGenerator;
|
||||||
|
EsPrint("File Manager: Type %I updated by application %d with name '%s'.\n",
|
||||||
|
type.identifier, applicationEntry.application, type.nameBytes, type.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
existing->applicationEntries.Add(applicationEntry);
|
||||||
|
|
||||||
|
if (matchValueBytes) {
|
||||||
|
uintptr_t p = 0, q = 0;
|
||||||
|
|
||||||
|
while (q <= matchValueBytes) {
|
||||||
|
if (q == matchValueBytes || matchValue[q] == ',') {
|
||||||
|
String string = StringFromLiteralWithSize(&matchValue[p], q - p);
|
||||||
|
p = q + 1;
|
||||||
|
|
||||||
|
if (StringStartsWith(string, StringFromLiteral("ext:"))) {
|
||||||
|
String extension = StringSlice(string, 4, -1);
|
||||||
|
bool isLower = true;
|
||||||
|
|
||||||
|
for (uintptr_t i = 0; i < extension.bytes; i++) {
|
||||||
|
if (EsCRTisupper(extension.text[i])) {
|
||||||
|
isLower = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extension.bytes && isLower) {
|
||||||
|
EsPrint("File Manager: Matching extension '%s' as %I.\n",
|
||||||
|
STRFMT(string), type.identifier);
|
||||||
|
*knownFileTypesByExtension.Put(STRING(extension)) = type.identifier;
|
||||||
|
} else {
|
||||||
|
EsPrint("File Manager: Invalid file type entry extension match '%s'.\n",
|
||||||
|
STRFMT(string));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
EsPrint("File Manager: Unknown file type entry match '%s'.\n", STRFMT(string));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
q++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// The UUID is invalid, ignore the entry.
|
||||||
|
if (hasUUID) EsPrint("File Manager: Discarding file type entry with invalid UUID.\n");
|
||||||
|
}
|
||||||
|
|
||||||
EsMemoryZero(&type, sizeof(type));
|
EsMemoryZero(&type, sizeof(type));
|
||||||
|
EsMemoryZero(&applicationEntry, sizeof(applicationEntry));
|
||||||
|
specifiedTextual = false, specifiedHasThumbnailGenerator = false, hasUUID = false;
|
||||||
|
matchValueBytes = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s = { .buffer = (char *) fileTypesBuffer.out, .bytes = fileTypesBuffer.bytes };
|
||||||
|
|
||||||
|
while (EsINIParse(&s)) {
|
||||||
|
if (0 == EsStringCompareRaw(s.key, s.keyBytes, EsLiteral("application"))) {
|
||||||
|
applicationEntry.application = EsIntegerParse(s.value, s.valueBytes);
|
||||||
|
} else if (0 == EsStringCompareRaw(s.key, s.keyBytes, EsLiteral("opens_any_textual_file"))) {
|
||||||
|
applicationEntry.open = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!EsINIPeek(&s) || !s.keyBytes) {
|
||||||
|
if (applicationEntry.open) {
|
||||||
|
for (uintptr_t i = 0; i < knownFileTypes.Length(); i++) {
|
||||||
|
if (knownFileTypes[i].textual) {
|
||||||
|
knownFileTypes[i].applicationEntries.Insert(applicationEntry, 0);
|
||||||
|
EsPrint("File Manager: Type %I is textual, so application %d can open it.\n",
|
||||||
|
knownFileTypes[i].identifier, applicationEntry.application);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EsMemoryZero(&applicationEntry, sizeof(applicationEntry));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EsUniqueIdentifier FileTypeMatchByExtension(String name) {
|
||||||
|
String extension = PathGetExtension(name);
|
||||||
|
char buffer[32];
|
||||||
|
uintptr_t i = 0;
|
||||||
|
|
||||||
|
for (; i < extension.bytes && i < 32; i++) {
|
||||||
|
buffer[i] = EsCRTtolower(extension.text[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return knownFileTypesByExtension.Get1(buffer, i);
|
||||||
|
}
|
||||||
|
|
||||||
FileType *FolderEntryGetType(Folder *folder, FolderEntry *entry) {
|
FileType *FolderEntryGetType(Folder *folder, FolderEntry *entry) {
|
||||||
|
EsUniqueIdentifier zeroIdentifier = {};
|
||||||
|
|
||||||
if (entry->isFolder) {
|
if (entry->isFolder) {
|
||||||
if (folder->itemHandler->getFileType != NamespaceDefaultGetFileType) {
|
if (folder->itemHandler->getFileType != NamespaceDefaultGetFileType) {
|
||||||
String path = StringAllocateAndFormat("%s%s", STRFMT(folder->path), STRFMT(entry->GetInternalName()));
|
String path = StringAllocateAndFormat("%s%s", STRFMT(folder->path), STRFMT(entry->GetInternalName()));
|
||||||
FileType *type = &knownFileTypes[folder->itemHandler->getFileType(path)];
|
FileType *type = &knownFileTypes[folder->itemHandler->getFileType(path)];
|
||||||
StringDestroy(&path);
|
StringDestroy(&path);
|
||||||
return type;
|
return type;
|
||||||
} else {
|
|
||||||
return &knownFileTypes[KNOWN_FILE_TYPE_DIRECTORY];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
String extension = entry->GetExtension();
|
|
||||||
char buffer[32];
|
|
||||||
uintptr_t i = 0;
|
|
||||||
|
|
||||||
for (; i < extension.bytes && i < 32; i++) {
|
|
||||||
if (EsCRTisupper(extension.text[i])) {
|
|
||||||
buffer[i] = EsCRTtolower(extension.text[i]);
|
|
||||||
} else {
|
|
||||||
buffer[i] = extension.text[i];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uintptr_t index = knownFileTypesByExtension.Get1(buffer, i);
|
return &knownFileTypes[KNOWN_FILE_TYPE_DIRECTORY];
|
||||||
return &knownFileTypes[index ? index : KNOWN_FILE_TYPE_UNKNOWN];
|
}
|
||||||
|
|
||||||
|
if (0 == EsMemoryCompare(&entry->contentType, &zeroIdentifier, sizeof(EsUniqueIdentifier))) {
|
||||||
|
entry->contentType = FileTypeMatchByExtension(entry->GetName());
|
||||||
|
entry->guessedContentType = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 == EsMemoryCompare(&entry->contentType, &zeroIdentifier, sizeof(EsUniqueIdentifier))) {
|
||||||
|
return &knownFileTypes[KNOWN_FILE_TYPE_UNKNOWN];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool typeFound = false;
|
||||||
|
uint32_t typeIndex = 0;
|
||||||
|
|
||||||
|
ES_MACRO_SEARCH(knownFileTypes.Length(), {
|
||||||
|
result = EsMemoryCompare(&entry->contentType, &knownFileTypes[index].identifier, sizeof(EsUniqueIdentifier));
|
||||||
|
}, typeIndex, typeFound);
|
||||||
|
|
||||||
|
return &knownFileTypes[typeFound ? typeIndex : KNOWN_FILE_TYPE_UNKNOWN];
|
||||||
}
|
}
|
||||||
|
|
|
@ -153,7 +153,7 @@ bool InstanceLoadFolder(Instance *instance, String path /* takes ownership */, i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
InstanceRefreshViewType(instance, false);
|
InstanceRefreshViewType(instance);
|
||||||
|
|
||||||
// Update the user interface.
|
// Update the user interface.
|
||||||
|
|
||||||
|
@ -168,11 +168,7 @@ bool InstanceLoadFolder(Instance *instance, String path /* takes ownership */, i
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstanceRefreshViewType(Instance *instance, bool startTransition) {
|
void InstanceRefreshViewType(Instance *instance) {
|
||||||
if (startTransition) {
|
|
||||||
EsElementStartTransition(instance->list, ES_TRANSITION_FADE, ES_ELEMENT_TRANSITION_CONTENT_ONLY, 1.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
EsCommandSetCheck(&instance->commandViewDetails, instance->viewSettings.viewType == VIEW_DETAILS ? ES_CHECK_CHECKED : ES_CHECK_UNCHECKED, false);
|
EsCommandSetCheck(&instance->commandViewDetails, instance->viewSettings.viewType == VIEW_DETAILS ? ES_CHECK_CHECKED : ES_CHECK_UNCHECKED, false);
|
||||||
EsCommandSetCheck(&instance->commandViewTiles, instance->viewSettings.viewType == VIEW_TILES ? ES_CHECK_CHECKED : ES_CHECK_UNCHECKED, false);
|
EsCommandSetCheck(&instance->commandViewTiles, instance->viewSettings.viewType == VIEW_TILES ? ES_CHECK_CHECKED : ES_CHECK_UNCHECKED, false);
|
||||||
EsCommandSetCheck(&instance->commandViewThumbnails, instance->viewSettings.viewType == VIEW_THUMBNAILS ? ES_CHECK_CHECKED : ES_CHECK_UNCHECKED, false);
|
EsCommandSetCheck(&instance->commandViewThumbnails, instance->viewSettings.viewType == VIEW_THUMBNAILS ? ES_CHECK_CHECKED : ES_CHECK_UNCHECKED, false);
|
||||||
|
@ -222,7 +218,11 @@ int InstanceCompareFolderEntries(FolderEntry *left, FolderEntry *right, uint16_t
|
||||||
if (sortColumn == COLUMN_NAME) {
|
if (sortColumn == COLUMN_NAME) {
|
||||||
result = EsStringCompare(STRING(left->GetName()), STRING(right->GetName()));
|
result = EsStringCompare(STRING(left->GetName()), STRING(right->GetName()));
|
||||||
} else if (sortColumn == COLUMN_TYPE) {
|
} else if (sortColumn == COLUMN_TYPE) {
|
||||||
result = EsStringCompare(STRING(left->GetExtension()), STRING(right->GetExtension()));
|
if (!left->isFolder) {
|
||||||
|
FileType *leftType = FolderEntryGetType(nullptr, left);
|
||||||
|
FileType *rightType = FolderEntryGetType(nullptr, right);
|
||||||
|
result = EsStringCompare(leftType->name, leftType->nameBytes, rightType->name, rightType->nameBytes);
|
||||||
|
}
|
||||||
} else if (sortColumn == COLUMN_SIZE) {
|
} else if (sortColumn == COLUMN_SIZE) {
|
||||||
if (right->size < left->size) result = 1;
|
if (right->size < left->size) result = 1;
|
||||||
else if (right->size > left->size) result = -1;
|
else if (right->size > left->size) result = -1;
|
||||||
|
@ -385,6 +385,8 @@ void InstanceAddContents(Instance *instance, HashTable *newEntries) {
|
||||||
EsListViewRemove(instance->list, 0, 0, oldListEntryCount);
|
EsListViewRemove(instance->list, 0, 0, oldListEntryCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO Optimize for each sorting mode.
|
||||||
|
// For example, sorting by type is pretty bad because it has to lookup file entry types to do each comparison.
|
||||||
InstanceSortListContents(instance->listContents.array, instance->listContents.Length(), instance->viewSettings.sortColumn);
|
InstanceSortListContents(instance->listContents.array, instance->listContents.Length(), instance->viewSettings.sortColumn);
|
||||||
|
|
||||||
if (instance->listContents.Length()) {
|
if (instance->listContents.Length()) {
|
||||||
|
@ -835,6 +837,8 @@ int ListCallback(EsElement *element, EsMessage *message) {
|
||||||
|
|
||||||
if (listEntry) {
|
if (listEntry) {
|
||||||
FolderEntry *entry = listEntry->entry;
|
FolderEntry *entry = listEntry->entry;
|
||||||
|
EsUniqueIdentifier applicationContentType = (EsUniqueIdentifier) {{ 0xBF, 0x88, 0xE4, 0xDD, 0x71, 0xE8, 0x5F, 0xDE,
|
||||||
|
0x16, 0xC5, 0xAF, 0x33, 0x41, 0xC7, 0xA2, 0x96 }};
|
||||||
|
|
||||||
if (entry->isFolder) {
|
if (entry->isFolder) {
|
||||||
String path = instance->folder->itemHandler->getPathForChild(instance->folder, entry);
|
String path = instance->folder->itemHandler->getPathForChild(instance->folder, entry);
|
||||||
|
@ -850,7 +854,7 @@ int ListCallback(EsElement *element, EsMessage *message) {
|
||||||
} else {
|
} else {
|
||||||
InstanceLoadFolder(instance, path);
|
InstanceLoadFolder(instance, path);
|
||||||
}
|
}
|
||||||
} else if (StringEquals(entry->GetExtension(), StringFromLiteral("esx"))) {
|
} else if (0 == EsMemoryCompare(&entry->contentType, &applicationContentType, sizeof(EsUniqueIdentifier))) {
|
||||||
// TODO Temporary.
|
// TODO Temporary.
|
||||||
String path = StringAllocateAndFormat("%s%s", STRFMT(instance->folder->path), STRFMT(entry->GetInternalName()));
|
String path = StringAllocateAndFormat("%s%s", STRFMT(instance->folder->path), STRFMT(entry->GetInternalName()));
|
||||||
|
|
||||||
|
@ -866,11 +870,18 @@ int ListCallback(EsElement *element, EsMessage *message) {
|
||||||
StringDestroy(&path);
|
StringDestroy(&path);
|
||||||
} else {
|
} else {
|
||||||
FileType *fileType = FolderEntryGetType(instance->folder, entry);
|
FileType *fileType = FolderEntryGetType(instance->folder, entry);
|
||||||
|
FileTypeApplicationEntry *typeEntry = nullptr;
|
||||||
|
|
||||||
if (fileType->openHandler) {
|
for (uintptr_t i = 0; i < fileType->applicationEntries.Length(); i++) {
|
||||||
|
if (fileType->applicationEntries[i].open) {
|
||||||
|
typeEntry = &fileType->applicationEntries[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeEntry) {
|
||||||
String path = StringAllocateAndFormat("%s%s", STRFMT(instance->folder->path), STRFMT(entry->GetInternalName()));
|
String path = StringAllocateAndFormat("%s%s", STRFMT(instance->folder->path), STRFMT(entry->GetInternalName()));
|
||||||
EsApplicationStartupRequest request = {};
|
EsApplicationStartupRequest request = {};
|
||||||
request.id = fileType->openHandler;
|
request.id = typeEntry->application;
|
||||||
request.filePath = path.text;
|
request.filePath = path.text;
|
||||||
request.filePathBytes = path.bytes;
|
request.filePathBytes = path.bytes;
|
||||||
request.flags = EsKeyboardIsCtrlHeld() || message->chooseItem.source == ES_LIST_VIEW_CHOOSE_ITEM_MIDDLE_CLICK
|
request.flags = EsKeyboardIsCtrlHeld() || message->chooseItem.source == ES_LIST_VIEW_CHOOSE_ITEM_MIDDLE_CLICK
|
||||||
|
|
|
@ -5,10 +5,10 @@ icon=icon_applications_fonts
|
||||||
[build]
|
[build]
|
||||||
source=apps/font_book.cpp
|
source=apps/font_book.cpp
|
||||||
|
|
||||||
[handler]
|
[file_type]
|
||||||
extension=ttf
|
actions=open
|
||||||
action=open
|
uuid=DA-BF-EC-06-31-8A-67-B6-E3-95-BC-D1-92-D2-9A-56
|
||||||
|
|
||||||
[handler]
|
[file_type]
|
||||||
extension=otf
|
actions=open
|
||||||
action=open
|
uuid=E7-2B-BB-E7-FF-75-32-E0-4E-75-41-C0-D2-ED-80-56
|
||||||
|
|
|
@ -736,14 +736,27 @@ int InstanceCallback(Instance *instance, EsMessage *message) {
|
||||||
EsBuffer buffer = { .out = _buffer, .bytes = _bufferBytes };
|
EsBuffer buffer = { .out = _buffer, .bytes = _bufferBytes };
|
||||||
buffer.fileStore = message->instanceSave.file;
|
buffer.fileStore = message->instanceSave.file;
|
||||||
|
|
||||||
|
EsUniqueIdentifier typeJPG = (EsUniqueIdentifier)
|
||||||
|
{{ 0xD8, 0xC2, 0x13, 0xB0, 0x53, 0x64, 0x82, 0x11, 0x48, 0x7B, 0x5B, 0x64, 0x0F, 0x92, 0xB9, 0x38 }};
|
||||||
|
EsUniqueIdentifier typeBMP = (EsUniqueIdentifier)
|
||||||
|
{{ 0x40, 0x15, 0xB7, 0x82, 0x99, 0x6D, 0xD5, 0x41, 0x96, 0xD5, 0x3B, 0x6D, 0xA6, 0x5F, 0x07, 0x34 }};
|
||||||
|
EsUniqueIdentifier typeTGA = (EsUniqueIdentifier)
|
||||||
|
{{ 0x69, 0x62, 0x4E, 0x28, 0xA1, 0xE1, 0x7B, 0x35, 0x64, 0x2E, 0x36, 0x01, 0x65, 0x91, 0xBE, 0xA1 }};
|
||||||
|
EsUniqueIdentifier typePNG = (EsUniqueIdentifier)
|
||||||
|
{{ 0x59, 0x21, 0x05, 0x4D, 0x34, 0x40, 0xAB, 0x61, 0xEC, 0xF9, 0x7D, 0x5C, 0x6E, 0x04, 0x96, 0xAE }};
|
||||||
|
|
||||||
if (0 == EsStringCompare(extension, extensionBytes, EsLiteral("jpg"))
|
if (0 == EsStringCompare(extension, extensionBytes, EsLiteral("jpg"))
|
||||||
|| 0 == EsStringCompare(extension, extensionBytes, EsLiteral("jpeg"))) {
|
|| 0 == EsStringCompare(extension, extensionBytes, EsLiteral("jpeg"))) {
|
||||||
|
EsFileStoreSetContentType(message->instanceSave.file, typeJPG);
|
||||||
stbi_write_jpg_to_func(WriteCallback, &buffer, width, height, 4, bits, 90);
|
stbi_write_jpg_to_func(WriteCallback, &buffer, width, height, 4, bits, 90);
|
||||||
} else if (0 == EsStringCompare(extension, extensionBytes, EsLiteral("bmp"))) {
|
} else if (0 == EsStringCompare(extension, extensionBytes, EsLiteral("bmp"))) {
|
||||||
|
EsFileStoreSetContentType(message->instanceSave.file, typeBMP);
|
||||||
stbi_write_bmp_to_func(WriteCallback, &buffer, width, height, 4, bits);
|
stbi_write_bmp_to_func(WriteCallback, &buffer, width, height, 4, bits);
|
||||||
} else if (0 == EsStringCompare(extension, extensionBytes, EsLiteral("tga"))) {
|
} else if (0 == EsStringCompare(extension, extensionBytes, EsLiteral("tga"))) {
|
||||||
|
EsFileStoreSetContentType(message->instanceSave.file, typeTGA);
|
||||||
stbi_write_tga_to_func(WriteCallback, &buffer, width, height, 4, bits);
|
stbi_write_tga_to_func(WriteCallback, &buffer, width, height, 4, bits);
|
||||||
} else {
|
} else {
|
||||||
|
EsFileStoreSetContentType(message->instanceSave.file, typePNG);
|
||||||
stbi_write_png_to_func(WriteCallback, &buffer, width, height, 4, bits, stride);
|
stbi_write_png_to_func(WriteCallback, &buffer, width, height, 4, bits, stride);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,10 +6,18 @@ use_single_process=1
|
||||||
[build]
|
[build]
|
||||||
source=apps/image_editor.cpp
|
source=apps/image_editor.cpp
|
||||||
|
|
||||||
[handler]
|
[file_type]
|
||||||
extension=jpg
|
actions=open
|
||||||
action=open
|
uuid=D8-C2-13-B0-53-64-82-11-48-7B-5B-64-0F-92-B9-38
|
||||||
|
|
||||||
[handler]
|
[file_type]
|
||||||
extension=png
|
actions=open
|
||||||
action=open
|
uuid=59-21-05-4D-34-40-AB-61-EC-F9-7D-5C-6E-04-96-AE
|
||||||
|
|
||||||
|
[file_type]
|
||||||
|
actions=open
|
||||||
|
uuid=40-15-B7-82-99-6D-D5-41-96-D5-3B-6D-A6-5F-07-34
|
||||||
|
|
||||||
|
[file_type]
|
||||||
|
actions=open
|
||||||
|
uuid=69-62-4E-28-A1-E1-7B-35-64-2E-36-01-65-91-BE-A1
|
||||||
|
|
|
@ -7,6 +7,6 @@ hidden=1
|
||||||
[build]
|
[build]
|
||||||
source=apps/markdown_viewer.cpp
|
source=apps/markdown_viewer.cpp
|
||||||
|
|
||||||
[handler]
|
[file_type]
|
||||||
extension=md
|
actions=open
|
||||||
action=open
|
uuid=B1-C3-9E-56-C9-B0-85-D6-AF-98-12-1C-2E-29-8D-24
|
||||||
|
|
|
@ -269,6 +269,23 @@ int InstanceCallback(Instance *instance, EsMessage *message) {
|
||||||
size_t byteCount;
|
size_t byteCount;
|
||||||
char *contents = EsTextboxGetContents(instance->textboxDocument, &byteCount);
|
char *contents = EsTextboxGetContents(instance->textboxDocument, &byteCount);
|
||||||
EsFileStoreWriteAll(message->instanceSave.file, contents, byteCount);
|
EsFileStoreWriteAll(message->instanceSave.file, contents, byteCount);
|
||||||
|
|
||||||
|
bool fileNameContainsExtension = false;
|
||||||
|
|
||||||
|
for (uintptr_t i = 0; i < (uintptr_t) message->instanceSave.nameOrPathBytes && i < 5; i++) {
|
||||||
|
if (message->instanceSave.nameOrPath[message->instanceSave.nameOrPathBytes - i - 1] == '.') {
|
||||||
|
fileNameContainsExtension = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileNameContainsExtension) {
|
||||||
|
// Don't set a content type, it should be matched from the file extension.
|
||||||
|
} else {
|
||||||
|
EsUniqueIdentifier plainText = (EsUniqueIdentifier)
|
||||||
|
{{ 0x25, 0x65, 0x4C, 0x89, 0xE7, 0x29, 0xEA, 0x9E, 0xB5, 0xBE, 0xB5, 0xCA, 0xA7, 0x60, 0xBD, 0x3D }};
|
||||||
|
EsFileStoreSetContentType(message->instanceSave.file, plainText);
|
||||||
|
}
|
||||||
|
|
||||||
EsHeapFree(contents);
|
EsHeapFree(contents);
|
||||||
EsInstanceSaveComplete(instance, message->instanceSave.file, true);
|
EsInstanceSaveComplete(instance, message->instanceSave.file, true);
|
||||||
} else if (message->type == ES_MSG_INSTANCE_OPEN) {
|
} else if (message->type == ES_MSG_INSTANCE_OPEN) {
|
||||||
|
|
|
@ -3,25 +3,8 @@ name=Text Editor
|
||||||
icon=icon_accessories_text_editor
|
icon=icon_accessories_text_editor
|
||||||
use_single_process=1
|
use_single_process=1
|
||||||
|
|
||||||
|
[file_type]
|
||||||
|
opens_any_textual_file=1
|
||||||
|
|
||||||
[build]
|
[build]
|
||||||
source=apps/text_editor.cpp
|
source=apps/text_editor.cpp
|
||||||
|
|
||||||
[handler]
|
|
||||||
extension=txt
|
|
||||||
action=open
|
|
||||||
|
|
||||||
[handler]
|
|
||||||
extension=cpp
|
|
||||||
action=open
|
|
||||||
|
|
||||||
[handler]
|
|
||||||
extension=h
|
|
||||||
action=open
|
|
||||||
|
|
||||||
[handler]
|
|
||||||
extension=c
|
|
||||||
action=open
|
|
||||||
|
|
||||||
[handler]
|
|
||||||
extension=ini
|
|
||||||
action=open
|
|
||||||
|
|
|
@ -1132,6 +1132,10 @@ EsMessage *EsMessageReceive() {
|
||||||
}
|
}
|
||||||
} else if (type == ES_MSG_INSTANCE_OPEN_DELAYED) {
|
} else if (type == ES_MSG_INSTANCE_OPEN_DELAYED) {
|
||||||
InstanceSendOpenMessage((EsInstance *) message.message._argument, false);
|
InstanceSendOpenMessage((EsInstance *) message.message._argument, false);
|
||||||
|
} else if (type == ES_MSG_INSTANCE_SAVE_COMPLETE_DELAYED) {
|
||||||
|
char buffer[1];
|
||||||
|
buffer[0] = DESKTOP_MSG_COMPLETE_SAVE;
|
||||||
|
MessageDesktop(buffer, 1, ((EsInstance *) message.message._argument)->window->handle);
|
||||||
} else if (type == ES_MSG_PRIMARY_CLIPBOARD_UPDATED) {
|
} else if (type == ES_MSG_PRIMARY_CLIPBOARD_UPDATED) {
|
||||||
EsInstance *instance = InstanceFromWindowID(message.message.tabOperation.id);
|
EsInstance *instance = InstanceFromWindowID(message.message.tabOperation.id);
|
||||||
if (instance) UIRefreshPrimaryClipboard(instance->window);
|
if (instance) UIRefreshPrimaryClipboard(instance->window);
|
||||||
|
@ -1237,9 +1241,9 @@ void EsInstanceSaveComplete(EsInstance *instance, EsFileStore *file, bool succes
|
||||||
APIInstance *apiInstance = (APIInstance *) instance->_private;
|
APIInstance *apiInstance = (APIInstance *) instance->_private;
|
||||||
|
|
||||||
if (instance) {
|
if (instance) {
|
||||||
char buffer[1];
|
// HACK Post this message so that our handle to the file is (hopefully) closed first.
|
||||||
buffer[0] = DESKTOP_MSG_COMPLETE_SAVE;
|
EsMessage m = { .type = ES_MSG_INSTANCE_SAVE_COMPLETE_DELAYED, ._argument = instance };
|
||||||
MessageDesktop(buffer, 1, instance->window->handle);
|
EsMessagePost(nullptr, &m);
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
const char *name;
|
const char *name;
|
||||||
|
|
|
@ -98,6 +98,7 @@ struct OpenDocument {
|
||||||
size_t pathBytes;
|
size_t pathBytes;
|
||||||
char *temporarySavePath;
|
char *temporarySavePath;
|
||||||
size_t temporarySavePathBytes;
|
size_t temporarySavePathBytes;
|
||||||
|
EsUniqueIdentifier temporarySavePreviousContentType; // The previous content type. Used as the default if the save operation does not set a new content type. This is useful for text/hex editors, where there is no intrinsic content type.
|
||||||
EsHandle readHandle;
|
EsHandle readHandle;
|
||||||
EsObjectID id;
|
EsObjectID id;
|
||||||
EsObjectID currentWriter;
|
EsObjectID currentWriter;
|
||||||
|
@ -2312,6 +2313,11 @@ void ApplicationInstanceRequestSave(ApplicationInstance *instance, const char *n
|
||||||
EsHeapFree(document->temporarySavePath);
|
EsHeapFree(document->temporarySavePath);
|
||||||
document->temporarySavePath = nullptr;
|
document->temporarySavePath = nullptr;
|
||||||
|
|
||||||
|
if (ES_SUCCESS != EsFileControl(document->readHandle, ES_FILE_CONTROL_GET_CONTENT_TYPE,
|
||||||
|
&document->temporarySavePreviousContentType, sizeof(EsUniqueIdentifier))) {
|
||||||
|
document->temporarySavePreviousContentType = {};
|
||||||
|
}
|
||||||
|
|
||||||
EsHandle fileHandle;
|
EsHandle fileHandle;
|
||||||
m.tabOperation.error = TemporaryFileCreate(&fileHandle, &document->temporarySavePath, &document->temporarySavePathBytes, ES_FILE_WRITE);
|
m.tabOperation.error = TemporaryFileCreate(&fileHandle, &document->temporarySavePath, &document->temporarySavePathBytes, ES_FILE_WRITE);
|
||||||
|
|
||||||
|
@ -2410,6 +2416,22 @@ void ApplicationInstanceCompleteSave(ApplicationInstance *fromInstance) {
|
||||||
document->readHandle = file.handle;
|
document->readHandle = file.handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EsUniqueIdentifier newContentType = {}, zeroContentType = {};
|
||||||
|
|
||||||
|
if (ES_SUCCESS == EsFileControl(document->readHandle, ES_FILE_CONTROL_GET_CONTENT_TYPE, &newContentType, sizeof(EsUniqueIdentifier))) {
|
||||||
|
if (0 == EsMemoryCompare(&newContentType, &zeroContentType, sizeof(EsUniqueIdentifier))
|
||||||
|
&& EsMemoryCompare(&document->temporarySavePreviousContentType, &zeroContentType, sizeof(EsUniqueIdentifier))) {
|
||||||
|
// The application did not set a content type, so use the previous content type of the file.
|
||||||
|
EsFileInformation write = EsFileOpen(document->path, document->pathBytes, ES_FILE_WRITE_SHARED | ES_NODE_FAIL_IF_NOT_FOUND);
|
||||||
|
|
||||||
|
if (write.error == ES_SUCCESS) {
|
||||||
|
EsFileControl(write.handle, ES_FILE_CONTROL_SET_CONTENT_TYPE,
|
||||||
|
&document->temporarySavePreviousContentType, sizeof(EsUniqueIdentifier));
|
||||||
|
EsHandleClose(write.handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
document->currentWriter = 0;
|
document->currentWriter = 0;
|
||||||
|
|
||||||
if (desktop.fileManager && desktop.fileManager->singleProcess) {
|
if (desktop.fileManager && desktop.fileManager->singleProcess) {
|
||||||
|
|
|
@ -95,7 +95,7 @@ EsError EsPathCreate(const char *path, ptrdiff_t pathBytes, EsNodeType type, boo
|
||||||
return ES_SUCCESS;
|
return ES_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
EsError EsFileControl(EsHandle file, EsFileControlOperation operation, const void *data, size_t dataBytes) {
|
EsError EsFileControl(EsHandle file, EsFileControlOperation operation, void *data, size_t dataBytes) {
|
||||||
return EsSyscall(ES_SYSCALL_FILE_CONTROL, file, operation, (uintptr_t) data, dataBytes);
|
return EsSyscall(ES_SYSCALL_FILE_CONTROL, file, operation, (uintptr_t) data, dataBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,6 +278,21 @@ void *EsFileStoreMap(EsFileStore *file, size_t *fileSize, uint32_t flags) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EsFileStoreSetContentType(EsFileStore *file, EsUniqueIdentifier identifier) {
|
||||||
|
if (file->type == FILE_STORE_HANDLE) {
|
||||||
|
EsFileControl(file->handle, ES_FILE_CONTROL_SET_CONTENT_TYPE, &identifier, sizeof(identifier));
|
||||||
|
} else if (file->type == FILE_STORE_PATH) {
|
||||||
|
EsFileInformation information = EsFileOpen(file->path, file->pathBytes, ES_FILE_WRITE | ES_NODE_CREATE_DIRECTORIES);
|
||||||
|
|
||||||
|
if (information.error == ES_SUCCESS) {
|
||||||
|
EsFileControl(file->handle, ES_FILE_CONTROL_SET_CONTENT_TYPE, &identifier, sizeof(identifier));
|
||||||
|
EsHandleClose(information.handle);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// The file store backend doesn't support this operation.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
EsError MountPointAdd(const char *prefix, size_t prefixBytes, EsHandle base, bool addedByApplication) {
|
EsError MountPointAdd(const char *prefix, size_t prefixBytes, EsHandle base, bool addedByApplication) {
|
||||||
EsMutexAcquire(&api.mountPointsMutex);
|
EsMutexAcquire(&api.mountPointsMutex);
|
||||||
bool duplicate = NodeFindMountPoint(prefix, prefixBytes, nullptr, true);
|
bool duplicate = NodeFindMountPoint(prefix, prefixBytes, nullptr, true);
|
||||||
|
@ -545,7 +560,7 @@ EsError EsFileWriteAllGather(const char *filePath, ptrdiff_t filePathLength, con
|
||||||
filePathLength = EsCStringLength(filePath);
|
filePathLength = EsCStringLength(filePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
EsFileInformation information = EsFileOpen((char *) filePath, filePathLength, ES_FILE_WRITE | ES_NODE_CREATE_DIRECTORIES);
|
EsFileInformation information = EsFileOpen(filePath, filePathLength, ES_FILE_WRITE | ES_NODE_CREATE_DIRECTORIES);
|
||||||
|
|
||||||
if (ES_SUCCESS != information.error) {
|
if (ES_SUCCESS != information.error) {
|
||||||
return information.error;
|
return information.error;
|
||||||
|
|
|
@ -763,6 +763,7 @@ inttype EsConnectionOpenFlags uint32_t none {
|
||||||
inttype EsFileControlOperation uint32_t none {
|
inttype EsFileControlOperation uint32_t none {
|
||||||
ES_FILE_CONTROL_FLUSH = 0 // data/dataBytes ignored
|
ES_FILE_CONTROL_FLUSH = 0 // data/dataBytes ignored
|
||||||
ES_FILE_CONTROL_SET_CONTENT_TYPE = 1 // data EsUniqueIdentifier; dataBytes ignored
|
ES_FILE_CONTROL_SET_CONTENT_TYPE = 1 // data EsUniqueIdentifier; dataBytes ignored
|
||||||
|
ES_FILE_CONTROL_GET_CONTENT_TYPE = 2 // data EsUniqueIdentifier; dataBytes ignored
|
||||||
};
|
};
|
||||||
|
|
||||||
inttype EsElementUpdateContentFlags uint32_t none {
|
inttype EsElementUpdateContentFlags uint32_t none {
|
||||||
|
@ -2142,7 +2143,7 @@ function EsError EsFileWriteAllGatherFromHandle(EsHandle handle, const void **da
|
||||||
function void *EsFileMap(STRING filePath, size_t *fileSize, uint32_t flags) @native();
|
function void *EsFileMap(STRING filePath, size_t *fileSize, uint32_t flags) @native();
|
||||||
function EsError EsFileCopy(STRING source, STRING destination, void **copyBuffer = ES_NULL, EsFileCopyCallback callback = ES_NULL, EsGeneric data = ES_NULL) @todo(); // If you are copying lots of files, you can reuse the temporary copy buffer by storing the output copyBuffer; call EsHeapFree on it after the last copy.
|
function EsError EsFileCopy(STRING source, STRING destination, void **copyBuffer = ES_NULL, EsFileCopyCallback callback = ES_NULL, EsGeneric data = ES_NULL) @todo(); // If you are copying lots of files, you can reuse the temporary copy buffer by storing the output copyBuffer; call EsHeapFree on it after the last copy.
|
||||||
|
|
||||||
function EsError EsFileControl(EsHandle file, EsFileControlOperation operation, const void *data, size_t dataBytes) @buffer_in(data, dataBytes);
|
function EsError EsFileControl(EsHandle file, EsFileControlOperation operation, void *data, size_t dataBytes) @buffer_out(data, dataBytes); // TODO This annotation is incorrect, it might be in or out depending on the operation.
|
||||||
function EsFileInformation EsFileOpen(STRING path, EsFileOpenFlags flags);
|
function EsFileInformation EsFileOpen(STRING path, EsFileOpenFlags flags);
|
||||||
function EsFileOffset EsFileGetSize(EsHandle handle);
|
function EsFileOffset EsFileGetSize(EsHandle handle);
|
||||||
function size_t EsFileReadSync(EsHandle file, EsFileOffset offset, size_t size, void *buffer) @buffer_out(buffer, size);
|
function size_t EsFileReadSync(EsHandle file, EsFileOffset offset, size_t size, void *buffer) @buffer_out(buffer, size);
|
||||||
|
@ -2162,6 +2163,7 @@ function bool EsFileStoreWriteAll(EsFileStore *file, const void *data, size_t da
|
||||||
function bool EsFileStoreAppend(EsFileStore *file, const void *data, size_t dataBytes) @buffer_in(data, dataBytes);
|
function bool EsFileStoreAppend(EsFileStore *file, const void *data, size_t dataBytes) @buffer_in(data, dataBytes);
|
||||||
function EsFileOffsetDifference EsFileStoreGetSize(EsFileStore *file); // Returns -1 on error.
|
function EsFileOffsetDifference EsFileStoreGetSize(EsFileStore *file); // Returns -1 on error.
|
||||||
function void *EsFileStoreMap(EsFileStore *file, size_t *fileSize, uint32_t flags) @native();
|
function void *EsFileStoreMap(EsFileStore *file, size_t *fileSize, uint32_t flags) @native();
|
||||||
|
function void EsFileStoreSetContentType(EsFileStore *file, EsUniqueIdentifier identifier);
|
||||||
|
|
||||||
// These calls require permission_all_files.
|
// These calls require permission_all_files.
|
||||||
function bool EsMountPointGetVolumeInformation(STRING prefix, EsVolumeInformation *information) @out(information); // Returns false if the mount point does not exist.
|
function bool EsMountPointGetVolumeInformation(STRING prefix, EsVolumeInformation *information) @out(information); // Returns false if the mount point does not exist.
|
||||||
|
@ -2394,6 +2396,7 @@ function bool EsUTF8IsValid(STRING input); // Does not check for surrogate chara
|
||||||
|
|
||||||
function double EsDoubleParse(STRING string, char **endptr) @native();
|
function double EsDoubleParse(STRING string, char **endptr) @native();
|
||||||
function int64_t EsIntegerParse(STRING text); // Parses in hexadecimal if the first two characters are '0x'.
|
function int64_t EsIntegerParse(STRING text); // Parses in hexadecimal if the first two characters are '0x'.
|
||||||
|
function EsUniqueIdentifier EsUniqueIdentifierParse(STRING text);
|
||||||
|
|
||||||
// CRT functions.
|
// CRT functions.
|
||||||
|
|
||||||
|
|
|
@ -425,6 +425,7 @@ extern "C" void *EsBufferWrite(EsBuffer *buffer, const void *source, size_t writ
|
||||||
#define ES_MSG_PING ((EsMessageType) (ES_MSG_SYSTEM_START + 0x203)) /* Sent by Desktop to check processes are processing messages. */
|
#define ES_MSG_PING ((EsMessageType) (ES_MSG_SYSTEM_START + 0x203)) /* Sent by Desktop to check processes are processing messages. */
|
||||||
#define ES_MSG_WAKEUP ((EsMessageType) (ES_MSG_SYSTEM_START + 0x204)) /* Sent to wakeup the message thread, so that it can process locally posted messages. */
|
#define ES_MSG_WAKEUP ((EsMessageType) (ES_MSG_SYSTEM_START + 0x204)) /* Sent to wakeup the message thread, so that it can process locally posted messages. */
|
||||||
#define ES_MSG_INSTANCE_OPEN_DELAYED ((EsMessageType) (ES_MSG_SYSTEM_START + 0x205))
|
#define ES_MSG_INSTANCE_OPEN_DELAYED ((EsMessageType) (ES_MSG_SYSTEM_START + 0x205))
|
||||||
|
#define ES_MSG_INSTANCE_SAVE_COMPLETE_DELAYED ((EsMessageType) (ES_MSG_SYSTEM_START + 0x206))
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -87,7 +87,7 @@ struct TextPiece {
|
||||||
uintptr_t glyphOffset;
|
uintptr_t glyphOffset;
|
||||||
size_t glyphCount;
|
size_t glyphCount;
|
||||||
uintptr_t start, end;
|
uintptr_t start, end;
|
||||||
bool isTabPiece;
|
bool isTabPiece, isEllipsisPiece;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TextLine {
|
struct TextLine {
|
||||||
|
@ -1829,6 +1829,7 @@ void TextAddEllipsis(EsTextPlan *plan, int32_t maximumLineWidth, bool needFinalE
|
||||||
piece.glyphOffset = plan->glyphInfos.Length();
|
piece.glyphOffset = plan->glyphInfos.Length();
|
||||||
piece.ascent = FontGetAscent (&plan->font) + plan->currentTextStyle->baselineOffset,
|
piece.ascent = FontGetAscent (&plan->font) + plan->currentTextStyle->baselineOffset,
|
||||||
piece.descent = -FontGetDescent(&plan->font) - plan->currentTextStyle->baselineOffset;
|
piece.descent = -FontGetDescent(&plan->font) - plan->currentTextStyle->baselineOffset;
|
||||||
|
piece.isEllipsisPiece = true;
|
||||||
|
|
||||||
for (uintptr_t i = 0; i < glyphCount; i++) {
|
for (uintptr_t i = 0; i < glyphCount; i++) {
|
||||||
if (!plan->glyphInfos.Add(glyphInfos[i])) break;
|
if (!plan->glyphInfos.Add(glyphInfos[i])) break;
|
||||||
|
@ -2295,7 +2296,7 @@ void DrawTextPiece(EsPainter *painter, EsTextPlan *plan, TextPiece *piece, TextL
|
||||||
|
|
||||||
// Draw the selection background.
|
// Draw the selection background.
|
||||||
|
|
||||||
if (selection->caret0 != selection->caret1 && !selection->hideCaret) {
|
if (selection->caret0 != selection->caret1 && !selection->hideCaret && !piece->isEllipsisPiece) {
|
||||||
int sCursorX = cursorX, selectionStartX = -1, selectionEndX = -1;
|
int sCursorX = cursorX, selectionStartX = -1, selectionEndX = -1;
|
||||||
|
|
||||||
for (uintptr_t i = 0; i < piece->glyphCount; i++) {
|
for (uintptr_t i = 0; i < piece->glyphCount; i++) {
|
||||||
|
|
|
@ -97,15 +97,13 @@ In the `[embed]` section there is a list of files that should be embedded into t
|
||||||
|
|
||||||
Each `[file_type]` section provides information about a file type.
|
Each `[file_type]` section provides information about a file type.
|
||||||
|
|
||||||
- `extension` Gives the file name extension for the file type.
|
- `match` Gives the file name extensions to match for the file type.
|
||||||
- `name` Gives the readable name of the file type, which will be shown to the user. TODO Translations.
|
- `name` Gives the readable name of the file type, which will be shown to the user. TODO Translations.
|
||||||
- `icon` Gives the name of the icon from `desktop/icons.header` to show for files of this type. TODO Bundled icons.
|
- `icon` Gives the name of the icon from `desktop/icons.header` to show for files of this type. TODO Bundled icons.
|
||||||
- `has_thumbnail_generator` Set to 1 if the file type has a thumbnail generator. Only images are supported at the moment. TODO Custom thumbnail generators.
|
- `has_thumbnail_generator` Set to 1 if the file type has a thumbnail generator. Only images are supported at the moment. TODO Custom thumbnail generators.
|
||||||
|
- `uuid` The EsUniqueIdentifier of the file type.
|
||||||
Each `[handler]` section describes this application's support to manage files of a given file type.
|
- `textual` Set to 1 if the file type can be read by plain text editors.
|
||||||
|
- `actions` The actions the application supports with this file type, e.g. `open`.
|
||||||
- `extension` The file name extension of the file type.
|
|
||||||
- `action` The action that this application support for the file type. Currently only "open" is supported.
|
|
||||||
|
|
||||||
### Standard build configuration options
|
### Standard build configuration options
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,119 @@
|
||||||
|
These are the EsUniqueIdentifier values for different file content types.
|
||||||
|
TODO Write up how the content type system works.
|
||||||
|
|
||||||
|
ELF executable
|
||||||
|
{ 0xAB, 0xDE, 0x98, 0xB5, 0x56, 0x2C, 0x04, 0xDF, 0x1E, 0x43, 0xC8, 0x10, 0x24, 0x63, 0xDB, 0xB8 }
|
||||||
|
|
||||||
|
esx application
|
||||||
|
{ 0xBF, 0x88, 0xE4, 0xDD, 0x71, 0xE8, 0x5F, 0xDE, 0x16, 0xC5, 0xAF, 0x33, 0x41, 0xC7, 0xA2, 0x96 }
|
||||||
|
|
||||||
|
plain text files
|
||||||
|
{ 0x25, 0x65, 0x4C, 0x89, 0xE7, 0x29, 0xEA, 0x9E, 0xB5, 0xBE, 0xB5, 0xCA, 0xA7, 0x60, 0xBD, 0x3D }
|
||||||
|
|
||||||
|
bochs config file
|
||||||
|
{ 0xFF, 0x92, 0xF0, 0x53, 0x28, 0x83, 0xDC, 0xF1, 0xBA, 0xDD, 0xDE, 0x79, 0x92, 0x33, 0x3F, 0x73 }
|
||||||
|
|
||||||
|
build core file
|
||||||
|
{ 0x6F, 0x2A, 0x23, 0x16, 0xAF, 0xA3, 0xD0, 0xFB, 0x95, 0x06, 0x52, 0xB3, 0x67, 0xFB, 0x37, 0xFA }
|
||||||
|
|
||||||
|
theme designer source file
|
||||||
|
{ 0x26, 0x4A, 0xE0, 0x6C, 0x0F, 0xE8, 0x2C, 0xE7, 0xF4, 0x6E, 0x4E, 0x76, 0x5B, 0x4A, 0xCF, 0x4F }
|
||||||
|
|
||||||
|
uxn rom
|
||||||
|
{ 0x76, 0xC2, 0xC1, 0x73, 0xB1, 0x20, 0x3D, 0x42, 0x70, 0xFD, 0xD4, 0xBD, 0x66, 0xE9, 0x2A, 0x39 }
|
||||||
|
|
||||||
|
static library .a
|
||||||
|
{ 0x7D, 0x39, 0xBF, 0x18, 0x9E, 0x07, 0xBC, 0xD3, 0x4F, 0x9F, 0x87, 0xEC, 0x6F, 0x70, 0x65, 0x5D }
|
||||||
|
|
||||||
|
libtool archive .la
|
||||||
|
{ 0x8F, 0x10, 0x4F, 0x33, 0x4A, 0xE5, 0x2D, 0xA7, 0x2A, 0x80, 0x2C, 0x4F, 0xEA, 0xE4, 0x99, 0xB1 }
|
||||||
|
|
||||||
|
compiled object .o
|
||||||
|
{ 0xB5, 0x19, 0xF2, 0x0D, 0xAD, 0x4F, 0xD4, 0xC9, 0xA4, 0xBF, 0x97, 0xE4, 0x5E, 0x4C, 0x55, 0x00 }
|
||||||
|
|
||||||
|
c source file
|
||||||
|
{ 0x36, 0x02, 0xD3, 0xAC, 0x6C, 0xDE, 0x8D, 0x31, 0xFA, 0x70, 0xB2, 0xDA, 0xFA, 0x81, 0x53, 0x69 }
|
||||||
|
|
||||||
|
c++ source file
|
||||||
|
{ 0x35, 0x84, 0xA6, 0x0E, 0x52, 0x28, 0xBA, 0xAB, 0xCA, 0x74, 0x14, 0xF4, 0xE1, 0x15, 0xCA, 0x5F }
|
||||||
|
|
||||||
|
c header file
|
||||||
|
{ 0xD1, 0x16, 0xC4, 0xC1, 0x7B, 0xC0, 0xED, 0x4F, 0xCA, 0xAC, 0x18, 0x05, 0x32, 0x1D, 0x56, 0x32 }
|
||||||
|
|
||||||
|
html file
|
||||||
|
{ 0x4A, 0x5A, 0x1C, 0xE5, 0xEE, 0x08, 0x6E, 0x04, 0x13, 0x9C, 0x6D, 0x05, 0x48, 0x5C, 0xE5, 0xD2 }
|
||||||
|
|
||||||
|
source template
|
||||||
|
{ 0x76, 0x35, 0xF3, 0xF5, 0xC2, 0x69, 0x8A, 0xA4, 0xE4, 0x68, 0x5F, 0xE5, 0x2C, 0x73, 0x10, 0xF9 }
|
||||||
|
|
||||||
|
linker script
|
||||||
|
{ 0x23, 0x56, 0xBC, 0xD4, 0x5A, 0xD6, 0x56, 0x08, 0x06, 0x61, 0x7C, 0x33, 0x38, 0x66, 0xD5, 0x1F }
|
||||||
|
|
||||||
|
markdown
|
||||||
|
{ 0xB1, 0xC3, 0x9E, 0x56, 0xC9, 0xB0, 0x85, 0xD6, 0xAF, 0x98, 0x12, 0x1C, 0x2E, 0x29, 0x8D, 0x24 }
|
||||||
|
|
||||||
|
UNIX package configuration
|
||||||
|
{ 0x74, 0x72, 0x01, 0x17, 0x97, 0x4B, 0x6B, 0x4B, 0x74, 0xCD, 0x18, 0x7C, 0x8F, 0x3C, 0x58, 0xBC }
|
||||||
|
|
||||||
|
python script
|
||||||
|
{ 0x77, 0x19, 0xBA, 0x87, 0x2E, 0xDB, 0x51, 0xA4, 0x71, 0x5D, 0xFF, 0x8D, 0x39, 0x86, 0x96, 0xF0 }
|
||||||
|
|
||||||
|
UNIX manual file
|
||||||
|
{ 0xDB, 0x72, 0xDD, 0x5D, 0x92, 0x54, 0x09, 0x1A, 0xC4, 0x16, 0xDD, 0x89, 0x0B, 0x13, 0x12, 0x1F }
|
||||||
|
|
||||||
|
application configuration file
|
||||||
|
{ 0x18, 0x8D, 0xD3, 0xAC, 0x35, 0xF5, 0xD3, 0x01, 0x8C, 0x66, 0xFD, 0x12, 0xE1, 0xED, 0xE2, 0x6F }
|
||||||
|
|
||||||
|
INI configuration file
|
||||||
|
{ 0x81, 0x72, 0x43, 0x29, 0xE5, 0x37, 0x89, 0x51, 0x8E, 0x22, 0xA0, 0x67, 0xA5, 0xB9, 0x42, 0x2C }
|
||||||
|
|
||||||
|
gzip archive
|
||||||
|
{ 0x7D, 0x93, 0x66, 0x74, 0x80, 0x0B, 0x64, 0x9F, 0x16, 0x5D, 0x44, 0xA5, 0x45, 0xFF, 0x80, 0xBF }
|
||||||
|
|
||||||
|
virtual drive image
|
||||||
|
{ 0xE1, 0x61, 0x4D, 0x0D, 0x32, 0xEC, 0xE0, 0x0F, 0x36, 0x7F, 0xE9, 0x7B, 0x3F, 0x16, 0x43, 0x02 }
|
||||||
|
|
||||||
|
jpeg image
|
||||||
|
{ 0xD8, 0xC2, 0x13, 0xB0, 0x53, 0x64, 0x82, 0x11, 0x48, 0x7B, 0x5B, 0x64, 0x0F, 0x92, 0xB9, 0x38 }
|
||||||
|
|
||||||
|
matroska video
|
||||||
|
{ 0x0D, 0xCA, 0x26, 0x92, 0x22, 0x44, 0xEB, 0x6B, 0xC6, 0xE9, 0x6C, 0x8E, 0xFC, 0x28, 0xD2, 0x8E }
|
||||||
|
|
||||||
|
3d object .obj
|
||||||
|
{ 0xF7, 0x81, 0xE9, 0x21, 0xDF, 0x89, 0x77, 0xD0, 0xC6, 0x97, 0xA8, 0x63, 0xF1, 0xF3, 0x4F, 0x63 }
|
||||||
|
|
||||||
|
png image
|
||||||
|
{ 0x59, 0x21, 0x05, 0x4D, 0x34, 0x40, 0xAB, 0x61, 0xEC, 0xF9, 0x7D, 0x5C, 0x6E, 0x04, 0x96, 0xAE }
|
||||||
|
|
||||||
|
tga image
|
||||||
|
{ 0x69, 0x62, 0x4E, 0x28, 0xA1, 0xE1, 0x7B, 0x35, 0x64, 0x2E, 0x36, 0x01, 0x65, 0x91, 0xBE, 0xA1 }
|
||||||
|
|
||||||
|
bmp image
|
||||||
|
{ 0x40, 0x15, 0xB7, 0x82, 0x99, 0x6D, 0xD5, 0x41, 0x96, 0xD5, 0x3B, 0x6D, 0xA6, 0x5F, 0x07, 0x34 }
|
||||||
|
|
||||||
|
truetype font
|
||||||
|
{ 0xDA, 0xBF, 0xEC, 0x06, 0x31, 0x8A, 0x67, 0xB6, 0xE3, 0x95, 0xBC, 0xD1, 0x92, 0xD2, 0x9A, 0x56 }
|
||||||
|
|
||||||
|
opentype font
|
||||||
|
{ 0xE7, 0x2B, 0xBB, 0xE7, 0xFF, 0x75, 0x32, 0xE0, 0x4E, 0x75, 0x41, 0xC0, 0xD2, 0xED, 0x80, 0x56 }
|
||||||
|
|
||||||
|
application data
|
||||||
|
{ 0xB5, 0x32, 0x22, 0x14, 0x01, 0xCB, 0xD0, 0x1D, 0xA2, 0x55, 0x08, 0xC7, 0x0D, 0x46, 0x86, 0x53 }
|
||||||
|
|
||||||
|
bash script
|
||||||
|
{ 0x66, 0x42, 0x88, 0xF9, 0xD1, 0x68, 0x47, 0xBF, 0x7F, 0x48, 0x82, 0x77, 0x2B, 0xE3, 0x39, 0xBA }
|
||||||
|
|
||||||
|
makefile
|
||||||
|
{ 0x3A, 0x58, 0x08, 0x24, 0x00, 0x75, 0xB5, 0x8B, 0xA8, 0x39, 0xD8, 0x37, 0x03, 0x6B, 0x20, 0x85 }
|
||||||
|
|
||||||
|
kernel module
|
||||||
|
{ 0x80, 0x6D, 0x8E, 0xD6, 0xC7, 0x45, 0xAD, 0xA7, 0x03, 0x5B, 0xB3, 0x64, 0xC5, 0x0A, 0xEE, 0xC6 }
|
||||||
|
|
||||||
|
ogg audio
|
||||||
|
{ 0xE5, 0x14, 0x14, 0xED, 0x4D, 0x67, 0xC0, 0xD0, 0x62, 0xA1, 0xA4, 0xD4, 0xF5, 0x82, 0xA7, 0x88 }
|
||||||
|
|
||||||
|
mp4 video
|
||||||
|
{ 0x02, 0x76, 0xE1, 0x41, 0xB8, 0x54, 0x19, 0xA9, 0x05, 0x8D, 0xC1, 0x3F, 0x6E, 0x8F, 0xD7, 0x9E }
|
||||||
|
|
||||||
|
wav audio
|
||||||
|
{ 0x87, 0xBC, 0xA1, 0xA1, 0x25, 0x76, 0x26, 0x5C, 0x8F, 0x94, 0xD6, 0xD8, 0x35, 0xB6, 0x7A, 0x9F }
|
|
@ -65,7 +65,7 @@ EsError FSNodeOpenHandle(KNode *node, uint32_t flags, uint8_t mode);
|
||||||
void FSNodeCloseHandle(KNode *node, uint32_t flags);
|
void FSNodeCloseHandle(KNode *node, uint32_t flags);
|
||||||
EsError FSNodeDelete(KNode *node);
|
EsError FSNodeDelete(KNode *node);
|
||||||
EsError FSNodeMove(KNode *node, KNode *destination, const char *newName, size_t nameNameBytes);
|
EsError FSNodeMove(KNode *node, KNode *destination, const char *newName, size_t nameNameBytes);
|
||||||
EsError FSFileResize(KNode *node, EsFileOffset newSizeBytes);
|
EsError FSFileResize(KNode *node, EsFileOffset newSizeBytes, bool growOnly = false);
|
||||||
ptrdiff_t FSDirectoryEnumerate(KNode *node, K_USER_BUFFER EsDirectoryChild *buffer, size_t bufferSize);
|
ptrdiff_t FSDirectoryEnumerate(KNode *node, K_USER_BUFFER EsDirectoryChild *buffer, size_t bufferSize);
|
||||||
EsError FSFileControlFlush(KNode *node);
|
EsError FSFileControlFlush(KNode *node);
|
||||||
EsError FSFileControlSetContentType(KNode *node, EsUniqueIdentifier identifier);
|
EsError FSFileControlSetContentType(KNode *node, EsUniqueIdentifier identifier);
|
||||||
|
@ -136,6 +136,7 @@ bool FSCheckPathForIllegalCharacters(const char *path, size_t pathBytes) {
|
||||||
EsError FSReadIntoCache(CCSpace *fileCache, void *buffer, EsFileOffset offset, EsFileOffset count) {
|
EsError FSReadIntoCache(CCSpace *fileCache, void *buffer, EsFileOffset offset, EsFileOffset count) {
|
||||||
FSFile *node = EsContainerOf(FSFile, cache, fileCache);
|
FSFile *node = EsContainerOf(FSFile, cache, fileCache);
|
||||||
|
|
||||||
|
// KWriterLockAssertLocked(&node->resizeLock);
|
||||||
KWriterLockTake(&node->writerLock, K_LOCK_SHARED);
|
KWriterLockTake(&node->writerLock, K_LOCK_SHARED);
|
||||||
EsDefer(KWriterLockReturn(&node->writerLock, K_LOCK_SHARED));
|
EsDefer(KWriterLockReturn(&node->writerLock, K_LOCK_SHARED));
|
||||||
|
|
||||||
|
@ -238,6 +239,7 @@ EsError FSFileCreateAndResizeOnFileSystem(FSFile *node, EsFileOffset fileSize) {
|
||||||
EsError FSWriteFromCache(CCSpace *fileCache, const void *buffer, EsFileOffset offset, EsFileOffset count) {
|
EsError FSWriteFromCache(CCSpace *fileCache, const void *buffer, EsFileOffset offset, EsFileOffset count) {
|
||||||
FSFile *node = EsContainerOf(FSFile, cache, fileCache);
|
FSFile *node = EsContainerOf(FSFile, cache, fileCache);
|
||||||
|
|
||||||
|
// KWriterLockAssertLocked(&node->resizeLock);
|
||||||
KWriterLockTake(&node->writerLock, K_LOCK_EXCLUSIVE);
|
KWriterLockTake(&node->writerLock, K_LOCK_EXCLUSIVE);
|
||||||
EsDefer(KWriterLockReturn(&node->writerLock, K_LOCK_EXCLUSIVE));
|
EsDefer(KWriterLockReturn(&node->writerLock, K_LOCK_EXCLUSIVE));
|
||||||
|
|
||||||
|
@ -335,7 +337,7 @@ void _FSFileResize(FSFile *file, EsFileOffset newSize) {
|
||||||
KMutexRelease(&file->fileSystem->moveMutex);
|
KMutexRelease(&file->fileSystem->moveMutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
EsError FSFileResize(KNode *node, EsFileOffset newSize) {
|
EsError FSFileResize(KNode *node, EsFileOffset newSize, bool growOnly) {
|
||||||
if (fs.shutdown) KernelPanic("FSFileResize - Attempting to resize a file after FSShutdown called.\n");
|
if (fs.shutdown) KernelPanic("FSFileResize - Attempting to resize a file after FSShutdown called.\n");
|
||||||
|
|
||||||
if (newSize > (EsFileOffset) 1 << 60) {
|
if (newSize > (EsFileOffset) 1 << 60) {
|
||||||
|
@ -350,7 +352,9 @@ EsError FSFileResize(KNode *node, EsFileOffset newSize) {
|
||||||
EsError error = ES_SUCCESS;
|
EsError error = ES_SUCCESS;
|
||||||
KWriterLockTake(&file->resizeLock, K_LOCK_EXCLUSIVE);
|
KWriterLockTake(&file->resizeLock, K_LOCK_EXCLUSIVE);
|
||||||
|
|
||||||
if (file->blockResize) {
|
if (growOnly && newSize <= file->directoryEntry->totalSize) {
|
||||||
|
// Nothing to do.
|
||||||
|
} else if (file->blockResize) {
|
||||||
error = ES_ERROR_OPERATION_BLOCKED;
|
error = ES_ERROR_OPERATION_BLOCKED;
|
||||||
} else if (!file->fileSystem->resize) {
|
} else if (!file->fileSystem->resize) {
|
||||||
error = ES_ERROR_FILE_ON_READ_ONLY_VOLUME;
|
error = ES_ERROR_FILE_ON_READ_ONLY_VOLUME;
|
||||||
|
@ -365,10 +369,8 @@ EsError FSFileResize(KNode *node, EsFileOffset newSize) {
|
||||||
ptrdiff_t FSFileWriteSync(KNode *node, K_USER_BUFFER const void *buffer, EsFileOffset offset, EsFileOffset bytes, uint32_t flags) {
|
ptrdiff_t FSFileWriteSync(KNode *node, K_USER_BUFFER const void *buffer, EsFileOffset offset, EsFileOffset bytes, uint32_t flags) {
|
||||||
if (fs.shutdown) KernelPanic("FSFileWriteSync - Attempting to write to a file after FSShutdown called.\n");
|
if (fs.shutdown) KernelPanic("FSFileWriteSync - Attempting to write to a file after FSShutdown called.\n");
|
||||||
|
|
||||||
if (offset + bytes > node->directoryEntry->totalSize) {
|
if (ES_SUCCESS != FSFileResize(node, offset + bytes, true /* growOnly */)) {
|
||||||
if (ES_SUCCESS != FSFileResize(node, offset + bytes)) {
|
return ES_ERROR_COULD_NOT_RESIZE_FILE;
|
||||||
return ES_ERROR_COULD_NOT_RESIZE_FILE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FSFile *file = (FSFile *) node;
|
FSFile *file = (FSFile *) node;
|
||||||
|
@ -426,8 +428,10 @@ EsError FSFileControlSetContentType(KNode *node, EsUniqueIdentifier identifier)
|
||||||
} else if (~node->fileSystem->flags & ES_VOLUME_STORES_CONTENT_TYPE) {
|
} else if (~node->fileSystem->flags & ES_VOLUME_STORES_CONTENT_TYPE) {
|
||||||
return ES_ERROR_UNSUPPORTED;
|
return ES_ERROR_UNSUPPORTED;
|
||||||
} else {
|
} else {
|
||||||
|
KWriterLockTake(&node->writerLock, K_LOCK_EXCLUSIVE);
|
||||||
node->directoryEntry->contentType = identifier;
|
node->directoryEntry->contentType = identifier;
|
||||||
__sync_fetch_and_or(&node->flags, NODE_MODIFIED); // Set the modified flag *after* making the modification.
|
__sync_fetch_and_or(&node->flags, NODE_MODIFIED); // Set the modified flag *after* making the modification.
|
||||||
|
KWriterLockReturn(&node->writerLock, K_LOCK_EXCLUSIVE);
|
||||||
return ES_SUCCESS;
|
return ES_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1015,9 +1019,11 @@ void FSNodeSynchronize(KNode *node) {
|
||||||
if (node->directoryEntry->type == ES_NODE_FILE) {
|
if (node->directoryEntry->type == ES_NODE_FILE) {
|
||||||
FSFile *file = (FSFile *) node;
|
FSFile *file = (FSFile *) node;
|
||||||
CCSpaceFlush(&file->cache);
|
CCSpaceFlush(&file->cache);
|
||||||
KWriterLockTake(&node->writerLock, K_LOCK_EXCLUSIVE);
|
KWriterLockTake(&file->resizeLock, K_LOCK_EXCLUSIVE);
|
||||||
|
KWriterLockTake(&file->writerLock, K_LOCK_EXCLUSIVE);
|
||||||
FSFileCreateAndResizeOnFileSystem(file, file->directoryEntry->totalSize);
|
FSFileCreateAndResizeOnFileSystem(file, file->directoryEntry->totalSize);
|
||||||
KWriterLockReturn(&node->writerLock, K_LOCK_EXCLUSIVE);
|
KWriterLockReturn(&file->writerLock, K_LOCK_EXCLUSIVE);
|
||||||
|
KWriterLockReturn(&file->resizeLock, K_LOCK_EXCLUSIVE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node->flags & NODE_MODIFIED) {
|
if (node->flags & NODE_MODIFIED) {
|
||||||
|
|
|
@ -697,10 +697,15 @@ bool MMHandlePageFault(MMSpace *space, uintptr_t address, unsigned faultFlags) {
|
||||||
pagesToRead = region->pageCount - (offsetIntoRegion + region->data.file.zeroedBytes) / K_PAGE_SIZE;
|
pagesToRead = region->pageCount - (offsetIntoRegion + region->data.file.zeroedBytes) / K_PAGE_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This shouldn't block, because mapped files cannot be resized.
|
||||||
|
KWriterLockTake(®ion->data.file.node->resizeLock, K_LOCK_SHARED);
|
||||||
|
|
||||||
EsError error = CCSpaceAccess(®ion->data.file.node->cache, (void *) address,
|
EsError error = CCSpaceAccess(®ion->data.file.node->cache, (void *) address,
|
||||||
offsetIntoRegion + region->data.file.offset, pagesToRead * K_PAGE_SIZE,
|
offsetIntoRegion + region->data.file.offset, pagesToRead * K_PAGE_SIZE,
|
||||||
CC_ACCESS_MAP, space, flags);
|
CC_ACCESS_MAP, space, flags);
|
||||||
|
|
||||||
|
KWriterLockReturn(®ion->data.file.node->resizeLock, K_LOCK_SHARED);
|
||||||
|
|
||||||
KMutexAcquire(®ion->data.mapMutex);
|
KMutexAcquire(®ion->data.mapMutex);
|
||||||
|
|
||||||
if (error != ES_SUCCESS) {
|
if (error != ES_SUCCESS) {
|
||||||
|
|
|
@ -1193,18 +1193,38 @@ SYSCALL_IMPLEMENT(ES_SYSCALL_FILE_CONTROL) {
|
||||||
|
|
||||||
if (file->directoryEntry->type != ES_NODE_FILE) {
|
if (file->directoryEntry->type != ES_NODE_FILE) {
|
||||||
SYSCALL_RETURN(ES_FATAL_ERROR_INCORRECT_NODE_TYPE, true);
|
SYSCALL_RETURN(ES_FATAL_ERROR_INCORRECT_NODE_TYPE, true);
|
||||||
} else if ((handle.flags & (ES_FILE_WRITE_SHARED | ES_FILE_WRITE)) == 0) {
|
|
||||||
SYSCALL_RETURN(ES_FATAL_ERROR_INCORRECT_FILE_ACCESS, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EsError error = ES_ERROR_UNSUPPORTED;
|
EsError error = ES_ERROR_UNSUPPORTED;
|
||||||
|
|
||||||
if (argument1 == ES_FILE_CONTROL_FLUSH) {
|
if (argument1 == ES_FILE_CONTROL_FLUSH) {
|
||||||
|
if ((handle.flags & (ES_FILE_WRITE_SHARED | ES_FILE_WRITE)) == 0) {
|
||||||
|
SYSCALL_RETURN(ES_FATAL_ERROR_INCORRECT_FILE_ACCESS, true);
|
||||||
|
}
|
||||||
|
|
||||||
error = FSFileControlFlush(file);
|
error = FSFileControlFlush(file);
|
||||||
} else if (argument1 == ES_FILE_CONTROL_SET_CONTENT_TYPE) {
|
} else if (argument1 == ES_FILE_CONTROL_SET_CONTENT_TYPE) {
|
||||||
|
if ((handle.flags & (ES_FILE_WRITE_SHARED | ES_FILE_WRITE)) == 0) {
|
||||||
|
SYSCALL_RETURN(ES_FATAL_ERROR_INCORRECT_FILE_ACCESS, true);
|
||||||
|
}
|
||||||
|
|
||||||
EsUniqueIdentifier identifier;
|
EsUniqueIdentifier identifier;
|
||||||
SYSCALL_READ(&identifier, argument2, sizeof(identifier));
|
SYSCALL_READ(&identifier, argument2, sizeof(identifier));
|
||||||
error = FSFileControlSetContentType(file, identifier);
|
error = FSFileControlSetContentType(file, identifier);
|
||||||
|
} else if (argument1 == ES_FILE_CONTROL_GET_CONTENT_TYPE) {
|
||||||
|
EsUniqueIdentifier identifier;
|
||||||
|
KWriterLockTake(&file->writerLock, K_LOCK_SHARED);
|
||||||
|
|
||||||
|
if (file->fileSystem->flags & ES_VOLUME_STORES_CONTENT_TYPE) {
|
||||||
|
identifier = file->directoryEntry->contentType;
|
||||||
|
error = ES_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
KWriterLockReturn(&file->writerLock, K_LOCK_SHARED);
|
||||||
|
|
||||||
|
if (error == ES_SUCCESS) {
|
||||||
|
SYSCALL_WRITE(argument2, &identifier, sizeof(EsUniqueIdentifier));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SYSCALL_RETURN(error, false);
|
SYSCALL_RETURN(error, false);
|
||||||
|
|
|
@ -9,10 +9,9 @@ custom_compile_command=cp root/Applications/POSIX/bin/bochs bin/Bochs
|
||||||
require=root/Applications/POSIX/bin/bochs
|
require=root/Applications/POSIX/bin/bochs
|
||||||
|
|
||||||
[file_type]
|
[file_type]
|
||||||
extension=bochsrc
|
match=ext:bochsrc
|
||||||
name=Bochs configuration
|
name=Bochs configuration
|
||||||
icon=icon_applications_development
|
icon=icon_applications_development
|
||||||
|
uuid=FF-92-F0-53-28-83-DC-F1-BA-DD-DE-79-92-33-3F-73
|
||||||
[handler]
|
actions=open
|
||||||
extension=bochsrc
|
textual=1
|
||||||
action=open
|
|
||||||
|
|
|
@ -9,11 +9,10 @@ link_flags=-lOSMesa -lstdc++ -lz
|
||||||
with_cstdlib=1
|
with_cstdlib=1
|
||||||
source=ports/mesa/obj_viewer.c
|
source=ports/mesa/obj_viewer.c
|
||||||
|
|
||||||
[handler]
|
|
||||||
extension=obj
|
|
||||||
action=open
|
|
||||||
|
|
||||||
[file_type]
|
[file_type]
|
||||||
extension=obj
|
match=ext:obj
|
||||||
name=3D model
|
name=3D model
|
||||||
icon=icon_model
|
icon=icon_model
|
||||||
|
uuid=F7-81-E9-21-DF-89-77-D0-C6-97-A8-63-F1-F3-4F-63
|
||||||
|
actions=open
|
||||||
|
textual=1
|
||||||
|
|
|
@ -6,11 +6,9 @@ hidden=1
|
||||||
source=ports/uxn/emulator.c
|
source=ports/uxn/emulator.c
|
||||||
compile_flags=-Wno-unknown-pragmas -Wno-unused-parameter
|
compile_flags=-Wno-unknown-pragmas -Wno-unused-parameter
|
||||||
|
|
||||||
[handler]
|
|
||||||
extension=uxn
|
|
||||||
action=open
|
|
||||||
|
|
||||||
[file_type]
|
[file_type]
|
||||||
extension=uxn
|
match=ext:uxn
|
||||||
name=Uxn ROM
|
name=Uxn ROM
|
||||||
icon=icon_unknown
|
icon=icon_unknown
|
||||||
|
uuid=76-C2-C1-73-B1-20-3D-42-70-FD-D4-BD-66-E9-2A-39
|
||||||
|
actions=open
|
||||||
|
|
|
@ -589,6 +589,16 @@ void _StringFormat(FormatCallback callback, void *callbackData, const char *form
|
||||||
callback('}', callbackData);
|
callback('}', callbackData);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
case 'I': {
|
||||||
|
EsUniqueIdentifier value = va_arg(arguments, EsUniqueIdentifier);
|
||||||
|
|
||||||
|
for (uintptr_t i = 0; i < 16; i++) {
|
||||||
|
if (i) callback('-', callbackData);
|
||||||
|
callback(hexChars[(value.d[i] & 0xF0) >> 4], callbackData);
|
||||||
|
callback(hexChars[(value.d[i] & 0xF)], callbackData);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
case 'X': {
|
case 'X': {
|
||||||
uintptr_t value = va_arg(arguments, uintptr_t);
|
uintptr_t value = va_arg(arguments, uintptr_t);
|
||||||
callback(hexChars[(value & 0xF0) >> 4], callbackData);
|
callback(hexChars[(value & 0xF0) >> 4], callbackData);
|
||||||
|
@ -920,6 +930,7 @@ int64_t EsStringParseInteger(const char **string, size_t *length, int base) {
|
||||||
int EsStringCompareRaw(const char *s1, ptrdiff_t length1, const char *s2, ptrdiff_t length2) {
|
int EsStringCompareRaw(const char *s1, ptrdiff_t length1, const char *s2, ptrdiff_t length2) {
|
||||||
if (length1 == -1) length1 = EsCStringLength(s1);
|
if (length1 == -1) length1 = EsCStringLength(s1);
|
||||||
if (length2 == -1) length2 = EsCStringLength(s2);
|
if (length2 == -1) length2 = EsCStringLength(s2);
|
||||||
|
if (s1 == s2 && length1 == length2) return 0;
|
||||||
|
|
||||||
while (length1 || length2) {
|
while (length1 || length2) {
|
||||||
if (!length1) return -1;
|
if (!length1) return -1;
|
||||||
|
@ -945,6 +956,7 @@ int EsStringCompare(const char *s1, ptrdiff_t _length1, const char *s2, ptrdiff_
|
||||||
if (_length1 == -1) _length1 = EsCStringLength(s1);
|
if (_length1 == -1) _length1 = EsCStringLength(s1);
|
||||||
if (_length2 == -1) _length2 = EsCStringLength(s2);
|
if (_length2 == -1) _length2 = EsCStringLength(s2);
|
||||||
size_t length1 = _length1, length2 = _length2;
|
size_t length1 = _length1, length2 = _length2;
|
||||||
|
if (s1 == s2 && length1 == length2) return 0;
|
||||||
|
|
||||||
while (length1 || length2) {
|
while (length1 || length2) {
|
||||||
if (!length1) return -1;
|
if (!length1) return -1;
|
||||||
|
@ -1072,6 +1084,28 @@ static int64_t ConvertCharacterToDigit(int character, int base) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EsUniqueIdentifier EsUniqueIdentifierParse(const char *text, ptrdiff_t bytes) {
|
||||||
|
if (bytes == -1) bytes = EsCStringLength(text);
|
||||||
|
if (bytes != 3 * 16 - 1) return {};
|
||||||
|
|
||||||
|
for (uintptr_t i = 0; i < 15; i++) {
|
||||||
|
if (text[i * 3 + 2] != '-') {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EsUniqueIdentifier identifier;
|
||||||
|
|
||||||
|
for (uintptr_t i = 0; i < 16; i++) {
|
||||||
|
int64_t a = ConvertCharacterToDigit(text[i * 3 + 0], 16);
|
||||||
|
int64_t b = ConvertCharacterToDigit(text[i * 3 + 1], 16);
|
||||||
|
if (a == -1 || b == -1) return {};
|
||||||
|
identifier.d[i] = a * 16 + b;
|
||||||
|
}
|
||||||
|
|
||||||
|
return identifier;
|
||||||
|
}
|
||||||
|
|
||||||
int64_t EsIntegerParse(const char *text, ptrdiff_t bytes) {
|
int64_t EsIntegerParse(const char *text, ptrdiff_t bytes) {
|
||||||
if (bytes == -1) bytes = EsCStringLength(text);
|
if (bytes == -1) bytes = EsCStringLength(text);
|
||||||
|
|
||||||
|
|
|
@ -694,12 +694,13 @@ void PrintTree(uint64_t block, int indent = 2, uint64_t lowerThan = -1) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void NewDirectoryEntry(DirectoryEntry *entry, uint8_t nodeType, EsUniqueIdentifier parentUID, const char *name) {
|
void NewDirectoryEntry(DirectoryEntry *entry, uint8_t nodeType, EsUniqueIdentifier parentUID, const char *name, EsUniqueIdentifier contentType) {
|
||||||
memcpy(entry->signature, ESFS_DIRECTORY_ENTRY_SIGNATURE, 8);
|
memcpy(entry->signature, ESFS_DIRECTORY_ENTRY_SIGNATURE, 8);
|
||||||
GenerateUniqueIdentifier(&entry->identifier, false);
|
GenerateUniqueIdentifier(&entry->identifier, false);
|
||||||
entry->attributeOffset = ESFS_ATTRIBUTE_OFFSET;
|
entry->attributeOffset = ESFS_ATTRIBUTE_OFFSET;
|
||||||
entry->nodeType = nodeType;
|
entry->nodeType = nodeType;
|
||||||
entry->parent = parentUID;
|
entry->parent = parentUID;
|
||||||
|
entry->contentType = contentType;
|
||||||
|
|
||||||
uint8_t *position = (uint8_t *) entry + entry->attributeOffset;
|
uint8_t *position = (uint8_t *) entry + entry->attributeOffset;
|
||||||
size_t newFilenameSize = ((strlen(name) + ESFS_FILENAME_HEADER_SIZE - 1) & ~7) + 8; // Size of name + size of header, rounded up to the nearest 8 bytes.
|
size_t newFilenameSize = ((strlen(name) + ESFS_FILENAME_HEADER_SIZE - 1) & ~7) + 8; // Size of name + size of header, rounded up to the nearest 8 bytes.
|
||||||
|
@ -736,7 +737,7 @@ void NewDirectoryEntry(DirectoryEntry *entry, uint8_t nodeType, EsUniqueIdentifi
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AddNode(const char *name, uint8_t nodeType, DirectoryEntry *outputEntry, DirectoryEntryReference *outputReference,
|
bool AddNode(const char *name, uint8_t nodeType, DirectoryEntry *outputEntry, DirectoryEntryReference *outputReference,
|
||||||
DirectoryEntryReference directoryReference) {
|
DirectoryEntryReference directoryReference, EsUniqueIdentifier contentType) {
|
||||||
// Log("add %s to %s\n", name, path);
|
// Log("add %s to %s\n", name, path);
|
||||||
|
|
||||||
// Step 1: Resize the directory so that it can fit another directory entry.
|
// Step 1: Resize the directory so that it can fit another directory entry.
|
||||||
|
@ -770,7 +771,7 @@ bool AddNode(const char *name, uint8_t nodeType, DirectoryEntry *outputEntry, Di
|
||||||
DirectoryEntry entry = {};
|
DirectoryEntry entry = {};
|
||||||
|
|
||||||
{
|
{
|
||||||
NewDirectoryEntry(&entry, nodeType, directory.identifier, name);
|
NewDirectoryEntry(&entry, nodeType, directory.identifier, name, contentType);
|
||||||
// Log("\tchild nodes: %ld\n", directoryAttribute->childNodes);
|
// Log("\tchild nodes: %ld\n", directoryAttribute->childNodes);
|
||||||
|
|
||||||
if (!AccessNode(&directory, &entry, (directoryAttribute->childNodes - 1) * sizeof(DirectoryEntry), sizeof(DirectoryEntry), &reference, false)) {
|
if (!AccessNode(&directory, &entry, (directoryAttribute->childNodes - 1) * sizeof(DirectoryEntry), sizeof(DirectoryEntry), &reference, false)) {
|
||||||
|
@ -1041,6 +1042,7 @@ typedef struct ImportNode {
|
||||||
const char *name, *path;
|
const char *name, *path;
|
||||||
struct ImportNode *children;
|
struct ImportNode *children;
|
||||||
bool isFile;
|
bool isFile;
|
||||||
|
EsUniqueIdentifier contentType;
|
||||||
} ImportNode;
|
} ImportNode;
|
||||||
|
|
||||||
int64_t Import(ImportNode node, DirectoryEntryReference parentDirectory) {
|
int64_t Import(ImportNode node, DirectoryEntryReference parentDirectory) {
|
||||||
|
@ -1059,7 +1061,7 @@ int64_t Import(ImportNode node, DirectoryEntryReference parentDirectory) {
|
||||||
DirectoryEntryReference reference;
|
DirectoryEntryReference reference;
|
||||||
DirectoryEntry entry;
|
DirectoryEntry entry;
|
||||||
|
|
||||||
if (!AddNode(node.children[i].name, ESFS_NODE_TYPE_FILE, &entry, &reference, parentDirectory)) {
|
if (!AddNode(node.children[i].name, ESFS_NODE_TYPE_FILE, &entry, &reference, parentDirectory, node.children[i].contentType)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1081,7 +1083,7 @@ int64_t Import(ImportNode node, DirectoryEntryReference parentDirectory) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
DirectoryEntryReference reference;
|
DirectoryEntryReference reference;
|
||||||
if (!AddNode(node.children[i].name, ESFS_NODE_TYPE_DIRECTORY, NULL, &reference, parentDirectory)) return -1;
|
if (!AddNode(node.children[i].name, ESFS_NODE_TYPE_DIRECTORY, NULL, &reference, parentDirectory, node.children[i].contentType)) return -1;
|
||||||
int64_t size = Import(node.children[i], reference);
|
int64_t size = Import(node.children[i], reference);
|
||||||
if (size == -1) return -1;
|
if (size == -1) return -1;
|
||||||
DirectoryEntry directory;
|
DirectoryEntry directory;
|
||||||
|
@ -1241,7 +1243,8 @@ bool Format(uint64_t driveSize, const char *volumeName, EsUniqueIdentifier osIns
|
||||||
DirectoryEntry entry;
|
DirectoryEntry entry;
|
||||||
EsUniqueIdentifier unused = {};
|
EsUniqueIdentifier unused = {};
|
||||||
|
|
||||||
NewDirectoryEntry(&entry, ESFS_NODE_TYPE_FILE, unused, "Kernel");
|
EsUniqueIdentifier elf = (EsUniqueIdentifier) {{ 0xAB, 0xDE, 0x98, 0xB5, 0x56, 0x2C, 0x04, 0xDF, 0x1E, 0x43, 0xC8, 0x10, 0x24, 0x63, 0xDB, 0xB8 }};
|
||||||
|
NewDirectoryEntry(&entry, ESFS_NODE_TYPE_FILE, unused, "Kernel", elf);
|
||||||
|
|
||||||
if (WriteDirectoryEntryReference(reference, &entry)) {
|
if (WriteDirectoryEntryReference(reference, &entry)) {
|
||||||
if (ResizeNode(&entry, kernelBytes)) {
|
if (ResizeNode(&entry, kernelBytes)) {
|
||||||
|
|
2
start.sh
2
start.sh
|
@ -1 +1 @@
|
||||||
cd "$(dirname "$0")" && mkdir -p bin && gcc -o bin/script util/script.c -g -Wall -Wextra -O2 -pthread -ldl && bin/script util/start.script options="`echo $@`"
|
cd "$(dirname "$0")" && mkdir -p bin && gcc -o bin/script util/script.c -g -Wall -Wextra -O2 -pthread && bin/script util/start.script options="`echo $@`"
|
||||||
|
|
|
@ -37,6 +37,7 @@ EsCommandSetCheck=35
|
||||||
EsTextboxGetContentsAsDouble=36
|
EsTextboxGetContentsAsDouble=36
|
||||||
EsFileStoreAppend=37
|
EsFileStoreAppend=37
|
||||||
EsBufferFlushToFileStore=38
|
EsBufferFlushToFileStore=38
|
||||||
|
EsFileStoreSetContentType=39
|
||||||
EsPathExists=40
|
EsPathExists=40
|
||||||
EsInstanceSetClassViewer=41
|
EsInstanceSetClassViewer=41
|
||||||
EsPathDelete=42
|
EsPathDelete=42
|
||||||
|
@ -494,3 +495,4 @@ EsRectangleContainsAll=493
|
||||||
EsListViewFixedItemSetEnumStringsForColumn=494
|
EsListViewFixedItemSetEnumStringsForColumn=494
|
||||||
EsImageDisplayGetImageHeight=495
|
EsImageDisplayGetImageHeight=495
|
||||||
EsDirectoryEnumerate=496
|
EsDirectoryEnumerate=496
|
||||||
|
EsUniqueIdentifierParse=497
|
||||||
|
|
|
@ -406,6 +406,91 @@ bool FileExists(const char *path) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef OS_ESSENCE
|
||||||
|
EsUniqueIdentifier MatchFileContentType(const char *pathBuffer) {
|
||||||
|
FILE *f = fopen(pathBuffer, "rb");
|
||||||
|
assert(f);
|
||||||
|
uint32_t elfSignature;
|
||||||
|
fread(&elfSignature, 1, sizeof(elfSignature), f);
|
||||||
|
bool isELFExecutable = elfSignature == 0x464C457F;
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
EsUniqueIdentifier t = { 0 };
|
||||||
|
|
||||||
|
#define ENDS_WITH(s) (strlen(pathBuffer) >= strlen(s) && 0 == strcmp(pathBuffer + strlen(pathBuffer) - strlen(s), s))
|
||||||
|
#define STARTS_WITH(s) (strlen(pathBuffer) >= strlen(s) && 0 == memcmp(pathBuffer, s, strlen(s)))
|
||||||
|
if (ENDS_WITH(".bochsrc"))
|
||||||
|
t = (EsUniqueIdentifier) {{ 0xFF, 0x92, 0xF0, 0x53, 0x28, 0x83, 0xDC, 0xF1, 0xBA, 0xDD, 0xDE, 0x79, 0x92, 0x33, 0x3F, 0x73 }};
|
||||||
|
else if (ENDS_WITH(".build_core"))
|
||||||
|
t = (EsUniqueIdentifier) {{ 0x6F, 0x2A, 0x23, 0x16, 0xAF, 0xA3, 0xD0, 0xFB, 0x95, 0x06, 0x52, 0xB3, 0x67, 0xFB, 0x37, 0xFA }};
|
||||||
|
else if (ENDS_WITH(".designer"))
|
||||||
|
t = (EsUniqueIdentifier) {{ 0x26, 0x4A, 0xE0, 0x6C, 0x0F, 0xE8, 0x2C, 0xE7, 0xF4, 0x6E, 0x4E, 0x76, 0x5B, 0x4A, 0xCF, 0x4F }};
|
||||||
|
else if (ENDS_WITH(".uxn"))
|
||||||
|
t = (EsUniqueIdentifier) {{ 0x76, 0xC2, 0xC1, 0x73, 0xB1, 0x20, 0x3D, 0x42, 0x70, 0xFD, 0xD4, 0xBD, 0x66, 0xE9, 0x2A, 0x39 }};
|
||||||
|
else if (ENDS_WITH(".a"))
|
||||||
|
t = (EsUniqueIdentifier) {{ 0x7D, 0x39, 0xBF, 0x18, 0x9E, 0x07, 0xBC, 0xD3, 0x4F, 0x9F, 0x87, 0xEC, 0x6F, 0x70, 0x65, 0x5D }};
|
||||||
|
else if (ENDS_WITH(".la"))
|
||||||
|
t = (EsUniqueIdentifier) {{ 0x8F, 0x10, 0x4F, 0x33, 0x4A, 0xE5, 0x2D, 0xA7, 0x2A, 0x80, 0x2C, 0x4F, 0xEA, 0xE4, 0x99, 0xB1 }};
|
||||||
|
else if (ENDS_WITH(".esx"))
|
||||||
|
t = (EsUniqueIdentifier) {{ 0xBF, 0x88, 0xE4, 0xDD, 0x71, 0xE8, 0x5F, 0xDE, 0x16, 0xC5, 0xAF, 0x33, 0x41, 0xC7, 0xA2, 0x96 }};
|
||||||
|
else if (ENDS_WITH(".o"))
|
||||||
|
t = (EsUniqueIdentifier) {{ 0xB5, 0x19, 0xF2, 0x0D, 0xAD, 0x4F, 0xD4, 0xC9, 0xA4, 0xBF, 0x97, 0xE4, 0x5E, 0x4C, 0x55, 0x00 }};
|
||||||
|
else if (ENDS_WITH(".c"))
|
||||||
|
t = (EsUniqueIdentifier) {{ 0x36, 0x02, 0xD3, 0xAC, 0x6C, 0xDE, 0x8D, 0x31, 0xFA, 0x70, 0xB2, 0xDA, 0xFA, 0x81, 0x53, 0x69 }};
|
||||||
|
else if (ENDS_WITH(".cpp"))
|
||||||
|
t = (EsUniqueIdentifier) {{ 0x35, 0x84, 0xA6, 0x0E, 0x52, 0x28, 0xBA, 0xAB, 0xCA, 0x74, 0x14, 0xF4, 0xE1, 0x15, 0xCA, 0x5F }};
|
||||||
|
else if (ENDS_WITH(".h"))
|
||||||
|
t = (EsUniqueIdentifier) {{ 0xD1, 0x16, 0xC4, 0xC1, 0x7B, 0xC0, 0xED, 0x4F, 0xCA, 0xAC, 0x18, 0x05, 0x32, 0x1D, 0x56, 0x32 }};
|
||||||
|
else if (ENDS_WITH(".html"))
|
||||||
|
t = (EsUniqueIdentifier) {{ 0x4A, 0x5A, 0x1C, 0xE5, 0xEE, 0x08, 0x6E, 0x04, 0x13, 0x9C, 0x6D, 0x05, 0x48, 0x5C, 0xE5, 0xD2 }};
|
||||||
|
else if (ENDS_WITH(".in"))
|
||||||
|
t = (EsUniqueIdentifier) {{ 0x76, 0x35, 0xF3, 0xF5, 0xC2, 0x69, 0x8A, 0xA4, 0xE4, 0x68, 0x5F, 0xE5, 0x2C, 0x73, 0x10, 0xF9 }};
|
||||||
|
else if (ENDS_WITH("/Makefile"))
|
||||||
|
t = (EsUniqueIdentifier) {{ 0x3A, 0x58, 0x08, 0x24, 0x00, 0x75, 0xB5, 0x8B, 0xA8, 0x39, 0xD8, 0x37, 0x03, 0x6B, 0x20, 0x85 }};
|
||||||
|
else if (ENDS_WITH(".ld") || STARTS_WITH("root/Applications/POSIX/x86_64-essence/lib/ldscripts/"))
|
||||||
|
t = (EsUniqueIdentifier) {{ 0x23, 0x56, 0xBC, 0xD4, 0x5A, 0xD6, 0x56, 0x08, 0x06, 0x61, 0x7C, 0x33, 0x38, 0x66, 0xD5, 0x1F }};
|
||||||
|
else if (ENDS_WITH(".md"))
|
||||||
|
t = (EsUniqueIdentifier) {{ 0xB1, 0xC3, 0x9E, 0x56, 0xC9, 0xB0, 0x85, 0xD6, 0xAF, 0x98, 0x12, 0x1C, 0x2E, 0x29, 0x8D, 0x24 }};
|
||||||
|
else if (ENDS_WITH(".pc"))
|
||||||
|
t = (EsUniqueIdentifier) {{ 0x74, 0x72, 0x01, 0x17, 0x97, 0x4B, 0x6B, 0x4B, 0x74, 0xCD, 0x18, 0x7C, 0x8F, 0x3C, 0x58, 0xBC }};
|
||||||
|
else if (ENDS_WITH(".py"))
|
||||||
|
t = (EsUniqueIdentifier) {{ 0x77, 0x19, 0xBA, 0x87, 0x2E, 0xDB, 0x51, 0xA4, 0x71, 0x5D, 0xFF, 0x8D, 0x39, 0x86, 0x96, 0xF0 }};
|
||||||
|
else if (ENDS_WITH(".sh"))
|
||||||
|
t = (EsUniqueIdentifier) {{ 0x66, 0x42, 0x88, 0xF9, 0xD1, 0x68, 0x47, 0xBF, 0x7F, 0x48, 0x82, 0x77, 0x2B, 0xE3, 0x39, 0xBA }};
|
||||||
|
else if (ENDS_WITH(".txt") || ENDS_WITH("/README") || ENDS_WITH("/LICENSE") || ENDS_WITH("/COPYING") || ENDS_WITH("/AUTHORS") || ENDS_WITH("/TODO")
|
||||||
|
|| ENDS_WITH("/BUGS") || ENDS_WITH("/NEWS") || ENDS_WITH("/CHANGES") || ENDS_WITH("/ReadMe") || ENDS_WITH(".LESSER"))
|
||||||
|
t = (EsUniqueIdentifier) {{ 0x25, 0x65, 0x4C, 0x89, 0xE7, 0x29, 0xEA, 0x9E, 0xB5, 0xBE, 0xB5, 0xCA, 0xA7, 0x60, 0xBD, 0x3D }};
|
||||||
|
else if (ENDS_WITH(".1") || ENDS_WITH(".7") || ENDS_WITH(".info") || ENDS_WITH(".info-1") || ENDS_WITH(".info-2"))
|
||||||
|
t = (EsUniqueIdentifier) {{ 0xDB, 0x72, 0xDD, 0x5D, 0x92, 0x54, 0x09, 0x1A, 0xC4, 0x16, 0xDD, 0x89, 0x0B, 0x13, 0x12, 0x1F }};
|
||||||
|
else if (ENDS_WITH(".conf") || ENDS_WITH(".bfd"))
|
||||||
|
t = (EsUniqueIdentifier) {{ 0x18, 0x8D, 0xD3, 0xAC, 0x35, 0xF5, 0xD3, 0x01, 0x8C, 0x66, 0xFD, 0x12, 0xE1, 0xED, 0xE2, 0x6F }};
|
||||||
|
else if (ENDS_WITH(".ini"))
|
||||||
|
t = (EsUniqueIdentifier) {{ 0x81, 0x72, 0x43, 0x29, 0xE5, 0x37, 0x89, 0x51, 0x8E, 0x22, 0xA0, 0x67, 0xA5, 0xB9, 0x42, 0x2C }};
|
||||||
|
else if (ENDS_WITH(".gz"))
|
||||||
|
t = (EsUniqueIdentifier) {{ 0x7D, 0x93, 0x66, 0x74, 0x80, 0x0B, 0x64, 0x9F, 0x16, 0x5D, 0x44, 0xA5, 0x45, 0xFF, 0x80, 0xBF }};
|
||||||
|
else if (ENDS_WITH(".img"))
|
||||||
|
t = (EsUniqueIdentifier) {{ 0xE1, 0x61, 0x4D, 0x0D, 0x32, 0xEC, 0xE0, 0x0F, 0x36, 0x7F, 0xE9, 0x7B, 0x3F, 0x16, 0x43, 0x02 }};
|
||||||
|
else if (ENDS_WITH(".jpg"))
|
||||||
|
t = (EsUniqueIdentifier) {{ 0xD8, 0xC2, 0x13, 0xB0, 0x53, 0x64, 0x82, 0x11, 0x48, 0x7B, 0x5B, 0x64, 0x0F, 0x92, 0xB9, 0x38 }};
|
||||||
|
else if (ENDS_WITH(".mkv"))
|
||||||
|
t = (EsUniqueIdentifier) {{ 0x0D, 0xCA, 0x26, 0x92, 0x22, 0x44, 0xEB, 0x6B, 0xC6, 0xE9, 0x6C, 0x8E, 0xFC, 0x28, 0xD2, 0x8E }};
|
||||||
|
else if (ENDS_WITH(".obj"))
|
||||||
|
t = (EsUniqueIdentifier) {{ 0xF7, 0x81, 0xE9, 0x21, 0xDF, 0x89, 0x77, 0xD0, 0xC6, 0x97, 0xA8, 0x63, 0xF1, 0xF3, 0x4F, 0x63 }};
|
||||||
|
else if (ENDS_WITH(".png"))
|
||||||
|
t = (EsUniqueIdentifier) {{ 0x59, 0x21, 0x05, 0x4D, 0x34, 0x40, 0xAB, 0x61, 0xEC, 0xF9, 0x7D, 0x5C, 0x6E, 0x04, 0x96, 0xAE }};
|
||||||
|
else if (ENDS_WITH(".ttf"))
|
||||||
|
t = (EsUniqueIdentifier) {{ 0xDA, 0xBF, 0xEC, 0x06, 0x31, 0x8A, 0x67, 0xB6, 0xE3, 0x95, 0xBC, 0xD1, 0x92, 0xD2, 0x9A, 0x56 }};
|
||||||
|
else if (STARTS_WITH("root/Applications/POSIX/share/bochs/"))
|
||||||
|
t = (EsUniqueIdentifier) {{ 0xB5, 0x32, 0x22, 0x14, 0x01, 0xCB, 0xD0, 0x1D, 0xA2, 0x55, 0x08, 0xC7, 0x0D, 0x46, 0x86, 0x53 }};
|
||||||
|
else if (isELFExecutable)
|
||||||
|
t = (EsUniqueIdentifier) {{ 0xAB, 0xDE, 0x98, 0xB5, 0x56, 0x2C, 0x04, 0xDF, 0x1E, 0x43, 0xC8, 0x10, 0x24, 0x63, 0xDB, 0xB8 }};
|
||||||
|
#undef ENDS_WITH
|
||||||
|
#undef STARTS_WITH
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void CreateImportNode(const char *path, ImportNode *node) {
|
void CreateImportNode(const char *path, ImportNode *node) {
|
||||||
char pathBuffer[256];
|
char pathBuffer[256];
|
||||||
|
|
||||||
|
@ -429,6 +514,7 @@ void CreateImportNode(const char *path, ImportNode *node) {
|
||||||
CreateImportNode(pathBuffer, &child);
|
CreateImportNode(pathBuffer, &child);
|
||||||
} else {
|
} else {
|
||||||
child.isFile = true;
|
child.isFile = true;
|
||||||
|
child.contentType = children[i].contentType;
|
||||||
}
|
}
|
||||||
|
|
||||||
child.name = EsStringAllocateAndFormat(NULL, "%s", children[i].nameBytes, children[i].name);
|
child.name = EsStringAllocateAndFormat(NULL, "%s", children[i].nameBytes, children[i].name);
|
||||||
|
@ -464,6 +550,7 @@ void CreateImportNode(const char *path, ImportNode *node) {
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
child.isFile = true;
|
child.isFile = true;
|
||||||
|
child.contentType = MatchFileContentType(pathBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
child.name = strdup(dir->d_name);
|
child.name = strdup(dir->d_name);
|
||||||
|
@ -549,20 +636,6 @@ bool MakeBundle(const char *outputFile, BundleInput *inputFiles, size_t inputFil
|
||||||
|
|
||||||
//////////////////////////////////
|
//////////////////////////////////
|
||||||
|
|
||||||
typedef struct FileType {
|
|
||||||
const char *extension;
|
|
||||||
const char *name;
|
|
||||||
const char *icon;
|
|
||||||
int id, openID;
|
|
||||||
bool hasThumbnailGenerator;
|
|
||||||
} FileType;
|
|
||||||
|
|
||||||
typedef struct Handler {
|
|
||||||
const char *extension;
|
|
||||||
const char *action;
|
|
||||||
int fileTypeID;
|
|
||||||
} Handler;
|
|
||||||
|
|
||||||
typedef struct DependencyFile {
|
typedef struct DependencyFile {
|
||||||
char path[256];
|
char path[256];
|
||||||
const char *name;
|
const char *name;
|
||||||
|
@ -573,11 +646,9 @@ typedef struct Application {
|
||||||
|
|
||||||
const char *name;
|
const char *name;
|
||||||
EsINIState *properties;
|
EsINIState *properties;
|
||||||
|
EsINIState *fileTypeLines;
|
||||||
int id;
|
int id;
|
||||||
|
|
||||||
FileType *fileTypes;
|
|
||||||
Handler *handlers;
|
|
||||||
|
|
||||||
bool install, builtin, withCStdLib;
|
bool install, builtin, withCStdLib;
|
||||||
|
|
||||||
const char **sources;
|
const char **sources;
|
||||||
|
@ -794,8 +865,6 @@ void ParseApplicationManifest(const char *manifestPath) {
|
||||||
application.manifestPath = manifestPath;
|
application.manifestPath = manifestPath;
|
||||||
application.compileFlags = "";
|
application.compileFlags = "";
|
||||||
application.linkFlags = "";
|
application.linkFlags = "";
|
||||||
Handler *handler = NULL;
|
|
||||||
FileType *fileType = NULL;
|
|
||||||
|
|
||||||
while (EsINIParse(&s)) {
|
while (EsINIParse(&s)) {
|
||||||
EsINIZeroTerminate(&s);
|
EsINIZeroTerminate(&s);
|
||||||
|
@ -815,27 +884,8 @@ void ParseApplicationManifest(const char *manifestPath) {
|
||||||
else INI_READ_BOOL(disabled, disabled);
|
else INI_READ_BOOL(disabled, disabled);
|
||||||
else INI_READ_BOOL(needs_native_toolchain, needsNativeToolchain);
|
else INI_READ_BOOL(needs_native_toolchain, needsNativeToolchain);
|
||||||
else if (s.keyBytes && s.valueBytes) arrput(application.properties, s);
|
else if (s.keyBytes && s.valueBytes) arrput(application.properties, s);
|
||||||
} else if (0 == strcmp(s.section, "handler")) {
|
|
||||||
if (!s.keyBytes) {
|
|
||||||
Handler _handler = {};
|
|
||||||
arrput(application.handlers, _handler);
|
|
||||||
handler = &arrlast(application.handlers);
|
|
||||||
}
|
|
||||||
|
|
||||||
INI_READ_STRING_PTR(extension, handler->extension);
|
|
||||||
INI_READ_STRING_PTR(action, handler->action);
|
|
||||||
} else if (0 == strcmp(s.section, "file_type")) {
|
} else if (0 == strcmp(s.section, "file_type")) {
|
||||||
if (!s.keyBytes) {
|
arrput(application.fileTypeLines, s);
|
||||||
FileType _fileType = {};
|
|
||||||
_fileType.id = nextID++;
|
|
||||||
arrput(application.fileTypes, _fileType);
|
|
||||||
fileType = &arrlast(application.fileTypes);
|
|
||||||
}
|
|
||||||
|
|
||||||
INI_READ_STRING_PTR(extension, fileType->extension);
|
|
||||||
INI_READ_STRING_PTR(name, fileType->name);
|
|
||||||
INI_READ_STRING_PTR(icon, fileType->icon);
|
|
||||||
INI_READ_BOOL(has_thumbnail_generator, fileType->hasThumbnailGenerator);
|
|
||||||
} else if (0 == strcmp(s.section, "embed") && s.key[0] != ';' && s.value[0]) {
|
} else if (0 == strcmp(s.section, "embed") && s.key[0] != ';' && s.value[0]) {
|
||||||
BundleInput input = { 0 };
|
BundleInput input = { 0 };
|
||||||
input.path = s.value;
|
input.path = s.value;
|
||||||
|
@ -884,38 +934,6 @@ void OutputSystemConfiguration() {
|
||||||
FileWrite(file, EsINIFormat(generalOptions + i, buffer, sizeof(buffer)), buffer);
|
FileWrite(file, EsINIFormat(generalOptions + i, buffer, sizeof(buffer)), buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uintptr_t i = 0; i < arrlenu(applications); i++) {
|
|
||||||
if (!applications[i].install) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uintptr_t j = 0; j < arrlenu(applications[i].handlers); j++) {
|
|
||||||
Handler *handler = applications[i].handlers + j;
|
|
||||||
int handlerID = applications[i].id;
|
|
||||||
|
|
||||||
for (uintptr_t i = 0; i < arrlenu(applications); i++) {
|
|
||||||
for (uintptr_t j = 0; j < arrlenu(applications[i].fileTypes); j++) {
|
|
||||||
FileType *fileType = applications[i].fileTypes + j;
|
|
||||||
|
|
||||||
if (0 == strcmp(handler->extension, fileType->extension)) {
|
|
||||||
handler->fileTypeID = fileType->id;
|
|
||||||
|
|
||||||
if (0 == strcmp(handler->action, "open")) {
|
|
||||||
fileType->openID = handlerID;
|
|
||||||
} else {
|
|
||||||
Log("Warning: unrecognised handler action '%s'.\n", handler->action);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!handler->fileTypeID) {
|
|
||||||
Log("Warning: could not find a file_type entry for handler with extension '%s' in application '%s'.\n",
|
|
||||||
handler->extension, applications[i].name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uintptr_t i = 0; i < arrlenu(applications); i++) {
|
for (uintptr_t i = 0; i < arrlenu(applications); i++) {
|
||||||
if (!applications[i].install) {
|
if (!applications[i].install) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -931,21 +949,13 @@ void OutputSystemConfiguration() {
|
||||||
FilePrintFormat(file, "%s=%s\n", applications[i].properties[j].key, applications[i].properties[j].value);
|
FilePrintFormat(file, "%s=%s\n", applications[i].properties[j].key, applications[i].properties[j].value);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uintptr_t j = 0; j < arrlenu(applications[i].fileTypes); j++) {
|
for (uintptr_t j = 0; j < arrlenu(applications[i].fileTypeLines); j++) {
|
||||||
FilePrintFormat(file, "\n[file_type]\n");
|
char buffer[4096];
|
||||||
FilePrintFormat(file, "id=%d\n", applications[i].fileTypes[j].id);
|
FileWrite(file, EsINIFormat(applications[i].fileTypeLines + j, buffer, sizeof(buffer)), buffer);
|
||||||
FilePrintFormat(file, "extension=%s\n", applications[i].fileTypes[j].extension);
|
|
||||||
FilePrintFormat(file, "name=%s\n", applications[i].fileTypes[j].name);
|
|
||||||
FilePrintFormat(file, "icon=%s\n", applications[i].fileTypes[j].icon);
|
|
||||||
FilePrintFormat(file, "open=%d\n", applications[i].fileTypes[j].openID);
|
|
||||||
FilePrintFormat(file, "has_thumbnail_generator=%d\n", applications[i].fileTypes[j].hasThumbnailGenerator);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uintptr_t j = 0; j < arrlenu(applications[i].handlers); j++) {
|
if (!applications[i].fileTypeLines[j].keyBytes) {
|
||||||
FilePrintFormat(file, "\n[handler]\n");
|
FilePrintFormat(file, "application=%d\n", applications[i].id);
|
||||||
FilePrintFormat(file, "action=%s\n", applications[i].handlers[j].action);
|
}
|
||||||
FilePrintFormat(file, "application=%d\n", applications[i].id);
|
|
||||||
FilePrintFormat(file, "file_type=%d\n", applications[i].handlers[j].fileTypeID);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1752,8 +1762,7 @@ int main(int argc, char **argv) {
|
||||||
arrfree(applications[i].sources);
|
arrfree(applications[i].sources);
|
||||||
arrfree(applications[i].dependencyFiles);
|
arrfree(applications[i].dependencyFiles);
|
||||||
arrfree(applications[i].bundleInputFiles);
|
arrfree(applications[i].bundleInputFiles);
|
||||||
arrfree(applications[i].fileTypes);
|
arrfree(applications[i].fileTypeLines);
|
||||||
arrfree(applications[i].handlers);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
arrfree(applicationManifests);
|
arrfree(applicationManifests);
|
||||||
|
|
|
@ -9,10 +9,9 @@ permission_run_temporary_application=1
|
||||||
source=util/build_core.c
|
source=util/build_core.c
|
||||||
|
|
||||||
[file_type]
|
[file_type]
|
||||||
extension=build_core
|
match=ext:build_core
|
||||||
name=Build config
|
name=Build config
|
||||||
icon=icon_text_x_makefile
|
icon=icon_text_x_makefile
|
||||||
|
uuid=6F-2A-23-16-AF-A3-D0-FB-95-06-52-B3-67-FB-37-FA
|
||||||
[handler]
|
actions=open
|
||||||
extension=build_core
|
textual=1
|
||||||
action=open
|
|
||||||
|
|
|
@ -3758,6 +3758,9 @@ int _UIInstanceCallback(EsInstance *instance, EsMessage *message) {
|
||||||
if (message->type == ES_MSG_INSTANCE_SAVE) {
|
if (message->type == ES_MSG_INSTANCE_SAVE) {
|
||||||
fileStore = message->instanceSave.file;
|
fileStore = message->instanceSave.file;
|
||||||
DocumentSave(nullptr);
|
DocumentSave(nullptr);
|
||||||
|
EsUniqueIdentifier type = (EsUniqueIdentifier)
|
||||||
|
{{ 0x26, 0x4A, 0xE0, 0x6C, 0x0F, 0xE8, 0x2C, 0xE7, 0xF4, 0x6E, 0x4E, 0x76, 0x5B, 0x4A, 0xCF, 0x4F }};
|
||||||
|
EsFileStoreSetContentType(fileStore, type);
|
||||||
EsInstanceSaveComplete(instance, fileStore, true);
|
EsInstanceSaveComplete(instance, fileStore, true);
|
||||||
fileStore = nullptr;
|
fileStore = nullptr;
|
||||||
} else if (message->type == ES_MSG_INSTANCE_OPEN) {
|
} else if (message->type == ES_MSG_INSTANCE_OPEN) {
|
||||||
|
|
|
@ -7,10 +7,8 @@ source=util/designer2.cpp
|
||||||
compile_flags=-D UI_ESSENCE -Wno-unused-parameter
|
compile_flags=-D UI_ESSENCE -Wno-unused-parameter
|
||||||
|
|
||||||
[file_type]
|
[file_type]
|
||||||
extension=designer
|
match=ext:designer
|
||||||
name=Designer file
|
name=Designer file
|
||||||
icon=icon_text_css
|
icon=icon_text_css
|
||||||
|
uuid=26-4A-E0-6C-0F-E8-2C-E7-F4-6E-4E-76-5B-4A-CF-4F
|
||||||
[handler]
|
actions=open
|
||||||
extension=designer
|
|
||||||
action=open
|
|
||||||
|
|
Loading…
Reference in New Issue