diff --git a/include/lgi/common/StructuredIo.h b/include/lgi/common/StructuredIo.h --- a/include/lgi/common/StructuredIo.h +++ b/include/lgi/common/StructuredIo.h @@ -1,337 +1,339 @@ #ifndef _STRUCTURED_IO_H_ #define _STRUCTURED_IO_H_ #include #include "lgi/common/Variant.h" #include "lgi/common/LMallocArray.h" #define DEBUG_STRUCT_IO 0 /* Generic base data field: (where size_t == EncSize/DecSize field) uint8_t type; // LVariantType size_t name_len; char name[name_len]; size_t data_size; uint8_t data[data_size]; Objects are wrapped with generic fields of the type GV_CUSTOM // start of object... ...array of member fields.... GV_VOID_PTR // end of object */ class LStructuredIo : public LMallocArray { bool Write = true; size_t Pos = 0; protected: bool CheckSpace(size_t bytes) { auto l = Pos + bytes; if (l > Length()) { if (!Length((l + 255) & ~0xff)) return false; LAssert(Length() >= l); } return true; } constexpr static int SevenMask = 0x7f; template void EncSize(LPointer &p, T sz) { if (!sz) *p.u8++ = 0; else while (sz) { uint8_t bits = sz & SevenMask; sz >>= 7; *p.u8++ = bits | (sz ? 0x80 : 0); } } template void DecSize(LPointer &p, T &sz) { sz = 0; uint8_t bits, shift = 0; do { bits = *p.u8++; sz |= ((T)bits & SevenMask) << shift; shift += 7; } while (bits & 0x80); } bool Encode(uint8_t type, const void *obj = NULL, size_t sz = 0, const char *name = NULL) { LPointer p; LAssert(Write); auto name_len = Strlen(name); if (!CheckSpace(1 + 8 + name_len + 8 + sz)) return false; p.u8 = AddressOf(Pos); #if DEBUG_STRUCT_IO auto type_addr = p.u8 - AddressOf(); #endif *p.u8++ = type; EncSize(p, name_len); if (name) { memcpy(p.u8, name, name_len); p.u8 += name_len; } EncSize(p, sz); #if DEBUG_STRUCT_IO auto data_addr = p.u8 - AddressOf(); #endif if (obj) { memcpy(p.u8, obj, sz); p.u8 += sz; } else LAssert(sz == 0); Pos = p.u8 - AddressOf(); #if DEBUG_STRUCT_IO LgiTrace("Encode(%i @ %i,%i sz=%i) after=%i\n", type, (int)type_addr, (int)data_addr, (int)sz, (int)Pos); #endif return true; } public: constexpr static LVariantType StartObject = GV_CUSTOM; constexpr static LVariantType EndObject = GV_VOID_PTR; constexpr static LVariantType EndRow = GV_NULL; LStructuredIo(bool write) : Write(write) { } bool GetWrite() { return Write; } size_t GetPos() { return Pos; } void Bool(bool &b, const char *name = NULL) { Encode(GV_BOOL, &b, sizeof(b), name); } template void Int(T &i, const char *name = NULL) { Encode(GV_INT64, &i, sizeof(i), name); } template void Float(T &f, const char *name = NULL) { Encode(GV_DOUBLE, &f, sizeof(f), name); } template void String(T *str, ssize_t sz = -1, const char *name = NULL) { if (sz < 0) sz = Strlen(str); Encode(sizeof(*str) > 1 ? GV_WSTRING : GV_STRING, str, sz * sizeof(T), name); } void String(LString &str, const char *name = NULL) { Encode(GV_STRING, str.Get(), str.Length(), name); } template void Binary(T *data, size_t elements, const char *name = NULL) { if (!data || elements == 0) return; Encode(GV_BINARY, data, sizeof(*data)*elements, name); } struct ObjRef { LStructuredIo *io; ObjRef(ObjRef &&r) : io(NULL) { LSwap(io, r.io); } ObjRef(LStructuredIo *parent) : io(parent) { } ~ObjRef() { if (io) io->Encode(EndObject); } }; ObjRef StartObj(const char *name) { ObjRef r(this); Encode(StartObject, NULL, 0, name); return r; } bool Decode(std::function callback, Progress *prog = NULL) { if (Length() == 0) return false; LPointer p; auto end = AddressOf()+Length(); p.u8 = AddressOf(Pos); #define CHECK_EOF(sz) if (p.u8 + sz > end) return false CHECK_EOF(1); #if DEBUG_STRUCT_IO auto type_addr = p.u8 - AddressOf(); #endif LVariantType type = (LVariantType)(*p.u8++); if (type >= GV_MAX) return false; if (type == EndRow) { if (callback) callback(type, 0, NULL, NULL); Pos = p.u8 - AddressOf(); return true; } size_t name_len, data_size; DecSize(p, name_len); CHECK_EOF(name_len); LString name(p.c, name_len); p.s8 += name_len; DecSize(p, data_size); CHECK_EOF(data_size); #if DEBUG_STRUCT_IO auto data_addr = p.u8 - AddressOf(); #endif if (callback) callback(type, data_size, p.u8, name); p.u8 += data_size; Pos = p.u8 - AddressOf(); #if DEBUG_STRUCT_IO LgiTrace("Decode(%i @ %i,%i sz=%i) after=%i\n", type, (int)type_addr, (int)data_addr, (int)data_size, (int)Pos); #endif return true; } bool Flush(LStream *s) { if (!s || !Write || Length() == 0) return false; (*this)[Pos++] = EndRow; bool Status = s->Write(AddressOf(), Pos) == Pos; Pos = 0; return Status; } }; #define IntIo(type) inline void StructIo(LStructuredIo &io, type i) { io.Int(i); } #define StrIo(type) inline void StructIo(LStructuredIo &io, type i) { io.String(i); } IntIo(char) IntIo(unsigned char) IntIo(short) IntIo(unsigned short) IntIo(int) IntIo(unsigned int) IntIo(int64_t) IntIo(uint64_t) +IntIo(size_t) +IntIo(ssize_t) StrIo(char*); StrIo(const char*); StrIo(wchar_t*); StrIo(const wchar_t*); inline void StructIo(LStructuredIo &io, LString &s) { if (io.GetWrite()) io.String(s.Get(), s.Length()); else io.Decode([&s](auto type, auto sz, auto ptr, auto name) { if (type == GV_STRING && ptr && sz > 0) s.Set((char*)ptr, sz); }); } inline void StructIo(LStructuredIo &io, LStringPipe &p) { // auto obj = io.StartObj("LStringPipe"); if (io.GetWrite()) { p.Iterate([&io](auto ptr, auto bytes) { io.String(ptr, bytes); return true; }); } else { io.Decode([&p](auto type, auto sz, auto ptr, auto name) { if (type == GV_STRING && ptr && sz > 0) p.Write(ptr, sz); }); } } inline void StructIo(LStructuredIo &io, LRect &r) { auto obj = io.StartObj("LRect"); io.Int(r.x1, "x1"); io.Int(r.y1, "y1"); io.Int(r.x2, "x2"); io.Int(r.y2, "y2"); } inline void StructIo(LStructuredIo &io, LColour &c) { auto obj = io.StartObj("LColour"); LString cs; uint8_t r, g, b, a; if (io.GetWrite()) { cs = LColourSpaceToString(c.GetColourSpace()); r = c.r(); g = c.g(); b = c.b(); a = c.a(); } io.String(cs, "colourSpace"); io.Int(r, "r"); io.Int(g, "g"); io.Int(b, "b"); io.Int(a, "a"); if (!io.GetWrite()) { c.SetColourSpace(LStringToColourSpace(cs)); c.r(r); c.g(g); c.b(b); c.a(a); } } -#endif \ No newline at end of file +#endif diff --git a/src/mac/cocoa/ClipBoard.mm b/src/mac/cocoa/ClipBoard.mm --- a/src/mac/cocoa/ClipBoard.mm +++ b/src/mac/cocoa/ClipBoard.mm @@ -1,337 +1,329 @@ // MacOSX Clipboard Implementation #include "lgi/common/Lgi.h" #include "lgi/common/ClipBoard.h" #define kClipboardTextType "public.utf16-plain-text" class LClipBoardPriv { public: LClipBoardPriv() { } ~LClipBoardPriv() { } }; /////////////////////////////////////////////////////////////////////////////////////////////// LClipBoard::LClipBoard(LView *o) { d = new LClipBoardPriv; Owner = o; Open = true; } LClipBoard::~LClipBoard() { DeleteObj(d); } bool LClipBoard::Empty() { LAutoPool Ap; bool Status = false; Txt.Empty(); wTxt.Reset(); NSPasteboard *pasteboard = [NSPasteboard generalPasteboard]; [pasteboard clearContents]; return Status; } bool LClipBoard::Text(const char *Str, bool AutoEmpty) { LAutoPool Ap; LAssert(AutoEmpty); // If the pasteboard isn't emptied we can't set it's value Empty(); Txt = Str; wTxt.Reset(); auto *pb = [NSPasteboard generalPasteboard]; auto *text = Txt.NsStr(); [pb addTypes:[NSArray arrayWithObject:NSPasteboardTypeString] owner:nil]; auto result = [pb setString:text forType:NSPasteboardTypeString]; LAssert(result); return result != 0; } char *LClipBoard::Text() { LAutoPool Ap; NSArray *classes = [[NSArray alloc] initWithObjects:[NSString class], nil]; NSArray *copiedItems = [[NSPasteboard generalPasteboard] readObjectsForClasses:classes options:[NSDictionary dictionary]]; if (copiedItems != nil) { for (NSString *s in copiedItems) { Txt = [s UTF8String]; break; } } [classes release]; return Txt; } bool LClipBoard::TextW(const char16 *Str, bool AutoEmpty) { bool Status = false; if (AutoEmpty) Empty(); Txt = Str; wTxt.Reset(); NSPasteboard *pasteboard = [NSPasteboard generalPasteboard]; NSArray *array = [NSArray arrayWithObject:Txt.NsStr()]; [pasteboard writeObjects:array]; return Status; } char16 *LClipBoard::TextW() { Text(); wTxt.Reset(Utf8ToWide(Txt)); return wTxt; } bool LClipBoard::Html(const char *doc, bool AutoEmpty) { return false; } LString LClipBoard::Html() { return LString(); } bool LClipBoard::Bitmap(LSurface *pDC, bool AutoEmpty) { LAssert(!"Not impl."); return false; } -bool LClipBoard::Bitmap(BitmapCb Callback) +void LClipBoard::Bitmap(BitmapCb Callback) { LAssert(!"Not impl."); - return false; } -LAutoPtr LClipBoard::Bitmap() +void LClipBoard::Files(FilesCb Callback) { LAssert(!"Not impl."); - return LAutoPtr(NULL); -} - -LString::Array LClipBoard::Files() -{ - LAssert(!"Not impl."); - return LString::Array(); } bool LClipBoard::Files(LString::Array &Paths, bool AutoEmpty) { LAssert(!"Not impl."); return false; } // This is a custom type to wrap binary data. NSString *const LBinaryDataPBoardType = @"com.memecode.lgi"; #if 0 static void _dump(const char *verb, uchar *ptr, uint64_t len) { printf("%s " LPrintfInt64 " bytes:\n", verb, len); for (int i=0; i mem; mem.Length(sizeof(LBinaryData_Hdr)+fmt.Length()); LBinaryData_Hdr *h = (LBinaryData_Hdr*)mem.AddressOf(); h->Magic = LBinaryData_Magic; h->FormatLen = (uint32_t)fmt.Length(); h->DataLen = Len; strcpy(h->Format, fmt); NSMutableData *m; self.data = m = [[NSMutableData alloc] initWithBytes:mem.AddressOf() length:mem.Length()]; [m appendBytes:ptr length:Len]; // _dump("Pasting", ptr, h->DataLen); } return self; } - (id)init:(NSData*)d { if ((self = [super init]) != nil) { self.data = d; } return self; } // Any of these parameters can be non-NULL if the caller doesn't care about them -- (bool)getData:(LString*)Format data:(LAutoPtr*)Ptr len:(ssize_t*)Len var:(LVariant*)Var +- (bool)getData:(LString*)Format data:(LString*)Str var:(LVariant*)Var { if (!self.data) { LgiTrace("%s:%i - No data object.\n", _FL); return false; } LArray mem; if (!mem.Length(MIN(self.data.length, 256))) { LgiTrace("%s:%i - Alloc failed.\n", _FL); return false; } [self.data getBytes:mem.AddressOf() length:mem.Length()]; LBinaryData_Hdr *h = (LBinaryData_Hdr*)mem.AddressOf(); if (h->Magic != LBinaryData_Magic) { LgiTrace("%s:%i - Data block missing magic.\n", _FL); return false; } - if (Len) - *Len = h->DataLen; + // h->DataLen; if (Format) *Format = h->Format; - if (Ptr) + if (Str) { - if (!Ptr->Reset(new uint8_t[h->DataLen])) + if (!Str->Length(h->DataLen)) { LgiTrace("%s:%i - Failed to alloc " LPrintfInt64 " bytes.\n", _FL, h->DataLen); return false; } NSRange r; r.location = sizeof(LBinaryData_Hdr) + h->FormatLen; r.length = h->DataLen; - [self.data getBytes:Ptr->Get() range:r]; + [self.data getBytes:Str->Get() range:r]; // _dump("Receiving", Ptr.Get(), h->DataLen); } else if (Var) { Var->Empty(); Var->Type = GV_BINARY; Var->Value.Binary.Length = h->DataLen; if ((Var->Value.Binary.Data = new char[h->DataLen])) { NSRange r; r.location = sizeof(LBinaryData_Hdr) + h->FormatLen; r.length = h->DataLen; [self.data getBytes:Var->Value.Binary.Data range:r]; } else return false; } return true; } - (nullable id)pasteboardPropertyListForType:(NSString *)type { if ([type isEqualToString:LBinaryDataPBoardType]) return self.data; return nil; } - (NSArray *)writableTypesForPasteboard:(NSPasteboard *)pasteboard { return [NSArray arrayWithObjects:LBinaryDataPBoardType, kUTTypeData, nil]; } + (NSPasteboardReadingOptions)readingOptionsForType:(NSString *)type pasteboard:(NSPasteboard *)pasteboard { return NSPasteboardReadingAsData; } + (NSArray *)readableTypesForPasteboard:(NSPasteboard *)pasteboard { return [NSArray arrayWithObjects:LBinaryDataPBoardType, kUTTypeData, nil]; } @end #define LGI_ClipBoardType "clipboard-binary" bool LClipBoard::Binary(FormatType Format, uchar *Ptr, ssize_t Len, bool AutoEmpty) { if (!Ptr || Len <= 0) return false; NSPasteboard *pasteboard = [NSPasteboard generalPasteboard]; auto data = [[LBinaryData alloc] init:LGI_ClipBoardType ptr:Ptr len:Len]; NSArray *array = [NSArray arrayWithObject:data]; [pasteboard clearContents]; auto r = [pasteboard writeObjects:array]; return r; } -bool LClipBoard::Binary(FormatType Format, LAutoPtr &Ptr, ssize_t *Len) +void LClipBoard::Binary(FormatType Format, BinaryCb Callback) { NSPasteboard *pasteboard = [NSPasteboard generalPasteboard]; auto d = [pasteboard dataForType:LBinaryDataPBoardType]; if (!d) { - LgiTrace("%s:%i - No LBinaryDataPBoardType data.\n", _FL); - return false; + if (Callback) Callback(LString(), "No LBinaryDataPBoardType data."); + return; } auto data = [[LBinaryData alloc] init:d]; if (!data) { - LgiTrace("%s:%i - LBinaryData alloc failed.\n", _FL); - return false; + if (Callback) Callback(LString(), "LBinaryData alloc failed."); + return; } - auto Status = [data getData:NULL data:&Ptr len:Len var:NULL]; + LString str; + [data getData:NULL data:&str var:NULL]; [data release]; - return Status; + if (Callback) Callback(str, LString()); }