flatbuffer from TS to C++ not working - c++
I have a flatbuffer schema for a message:
table NodeConstructionInfo {
type:string (id: 0, required);
name:string (id: 1, required);
}
table AddNodeRequest {
graphId:string (id:0, required);
node:NodeConstructionInfo (id:1, required);
}
which I construct (write) in TypeScript and receive (read) in C++:
let builder = new flatbuffers.Builder(356);
let offGraphId = builder.createString("2992ebff-c950-4184-8876-5fe6ac029aa5");
let offType = builder.createString("MySuperDuperNode");
let offName = builder.createString("DummyNode");
sz.NodeConstructionInfo.startNodeConstructionInfo(builder);
sz.NodeConstructionInfo.addName(builder, offName);
sz.NodeConstructionInfo.addType(builder, offType);
let off = sz.NodeConstructionInfo.endNodeConstructionInfo(builder);
sz.AddNodeRequest.startAddNodeRequest(builder);
sz.AddNodeRequest.addGraphId(builder, offGraphId);
sz.AddNodeRequest.addNode(builder, off);
off = sz.AddNodeRequest.endAddNodeRequest(builder);
builder.finish(off);
let requestPayload = builder.asUint8Array();
In C++ I receive the 356 bytes (requestPayload) and try to verify it by doing
flatbuffers::Verifier v(buffer.getData(), buffer.getSize());
v.VerifyBuffer<AddNodeRequest>();
which always fails in <flatbuffers/flatbuffers.h> at:
template<typename T>
bool VerifyBufferFromStart(const char *identifier, const uint8_t *start)
{
...
// Call T::Verify, which must be in the generated code for this type.
auto o = VerifyOffset(start); <--- HERE (the first read flatbuffers::uoffset_t should not be 0 (don't know why)?)
...
}
Am I missing some important detail?
The buffer looks like
PostData received:
'\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,
\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,
\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,
\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,
\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,
\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,
\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,
\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,
\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,
\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,
\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,\x00,
\x00,\f,\x00,\x00,\x00,\b,\x00,\f,\x00,\b,\x00,\x04,\x00,\b,\x00,\x00,\x00,\x10,\x00,\x00,\x00,#,\x00,\x00,
\x00,\b,\x00,\f,\x00,\x04,\x00,\b,\x00,\b,\x00,\x00,\x00, ,\x00,\x00,\x00,\x04,\x00,\x00,\x00,\x10,\x00,\x00,
\x00,M,y,S,u,p,e,r,D,u,p,e,r,N,o,d,e,\x00,\x00,\x00,\x00,\t,\x00,\x00,\x00,D,u,m,m,y,N,o,d,e,
\x00,\x00,\x00,$,\x00,\x00,\x00,2,9,9,2,e,b,f,f,-,c,9,5,0,-,4,1,8,4,-,8,8,7,6,-,5,f,e,6,a,c,0,2,9,a,a,5,
\x00,\x00,\x00,\x00
Reading messages in TypeScript written from C++ works... (?)
flatbuffer version 1.9.0
As your buffer dump shows, the problem is that it contains a lot of leading zeros. A FlatBuffer while being constructed actually may contain leading zeroes (since it is being constructed in a larger buffer backwards), but asUint8Array normally takes care of trimming that down to just the array you need. So either you're not actually using asUint8Array in your actual code, or the zeroes are being pre-pended by some other code.
The problem is the position and how data is sent in the post. The buffer must be sliced to the position specified in ByteBuffer and the post must be send like a Blob.
builder.finish(end);
var buffer: flatbuffers.ByteBuffer = builder.dataBuffer();
var data: Uint8Array = buffer.bytes().slice(buffer.position());
this.http.post(environment.apiRoot + "hello", new Blob([data])).subscribe(
() => {},
(error) => {}
);
Related
How do I save the results of a MKLocalSearch to an Array?
I am experiencing a bit of trouble, while working on my app in SwiftUI. I want to append relevant data, summarized in an object, to an array and return this. While returning the array, I could see by debugging, that it is empty. Debugging in the for loop showed me, that location objects are created and appended, but are not being "saved" in the array. The "mapItems" array on the other hand has lots of members. What am I missing? Here is the method I came up with: func searchForLocation(searchTerm: String) -> Array<Location>{ var locations = [Location] let searchReqeust = MKLocalSearch.Request() searchRequest.region = region //region is a published variable and is determined before searchRequest.naturalLanguageQuery = searchTerm let search = MKLocalSearch(request: searchRequest) search.start{response, error in //error handling . . . //empty response.mapItems handling . . . for item in response!mapItems{ let location = createLocationFromItem(item: item) locations.append(location) } } return locations } My locations class if following: class Location: Identifiable{ var id= UUID() var coordinates: CLLocationCoordinate2d //And its proper init method }
Your searchForLocation has an asynchronous function inside (search.start{...}), and your code returns before it has finished getting the results. To "wait" for the results use a completion/closure handler, something like this: func searchForLocation(searchTerm: String, completion: #escaping ([Location]) -> ()) { var locations = [Location]() // <-- here // .... search.start{response, error in // <-- here asynchronous function //... todo deal with errors, eg return completion([]) for item in response!mapItems { let location = createLocationFromItem(item: item) locations.append(location) } completion(locations) // <- here return when finished } } and call the function like this: searchForLocation(searchTerm: "Tokyo") { results in print("\(results)") // <-- here results available, not before } I suggest you read-up on how to create and use asynchronous functions, these are important concepts to master to code effectively in Swift.
How to pass optional<vector<optional<uuid>>> from C++ to Swift?
I have following problem: I have iOS application with C++ core. Data is bridged through C++<->ObjCpp<->ObjC chain, data structures are later imported in swift from ObjC. I have optional<vector<optional>> in one of my structures and there is problem with importing it. Vector is converted to NSList, which is populated by data. Because there can't be nil in NSList, I add NSNull to it. If vector isn't optional - I can work with it in Swift, though it isn't very convenient. let arr = struct.myArray as NSArray var swift_arr: [UUID?] = [] for val in arr { if val is NSNull { swift_arr.append( nil ) } else if val is NSUUID { swift_arr.append( val as? UUID ) } else { fatalError() } } But if array is optional - there is big problem, because when I try to bind optional value, Swift tries to convert it to [UUID?] from NSArray, and when there is NSNull among NSUUIDs, it crashes, because NSNull cannot be converted to UUID. Is there any proper way to handle such arrays?
How do I get difficulty over time from Kulupu (polkadotjs)?
// Import import { ApiPromise, WsProvider } from "#polkadot/api"; // Construct /* https://rpc.kulupu.network https://rpc.kulupu.network/ws https://rpc.kulupu.corepaper.org https://rpc.kulupu.corepaper.org/ws */ (async () => { //const wsProvider = new WsProvider('wss://rpc.polkadot.io'); const wsProvider = new WsProvider("wss://rpc.kulupu.network/ws"); const api = await ApiPromise.create({ provider: wsProvider }); // Do something const chain = await api.rpc.system.chain(); console.log(`You are connected to ${chain} !`); console.log(await api.query.difficulty.pastDifficultiesAndTimestamps.toJSON()); console.log(api.genesisHash.toHex()); })();
The storage item pastDifficultiesAndTimestamps only holds the last 60 blocks worth of data. For getting that information you just need to fix the following: console.log(await api.query.difficulty.pastDifficultiesAndTimestamps()); If you want to query the difficulty of a blocks in general, a loop like this will work: let best_block = await api.derive.chain.bestNumber() // Could be 0, but that is a lot of queries... let first_block = best_block - 100; for (let block = first_block; block < best_block; block++) { let block_hash = await api.rpc.chain.getBlockHash(block); let difficulty = await api.query.difficulty.currentDifficulty.at(block_hash); console.log(block, difficulty) } Note that this requires an archive node which has informaiton about all the blocks. Otherwise, by default, a node only stores ~256 previous blocks before state pruning cleans things up. If you want to see how to make a query like this, but much more efficiently, look at my blog post here: https://www.shawntabrizi.com/substrate/porting-web3-js-to-polkadot-js/
Swift 3: how to supply a C-style 'void *' object to iOS frameworks for use with callbacks? [duplicate]
This question already has answers here: How to cast self to UnsafeMutablePointer<Void> type in swift (4 answers) Closed 5 years ago. Foundation is chock full of functions that take an opaque void *info then later vend it back. In pre-ARC Objective C days, you could retain an object, supply it, then when it was handed back to your callback release it. For example, CGDataProviderRef CGDataProviderCreateWithData(void *info, const void *data, size_t size, CGDataProviderReleaseDataCallback releaseData); typedef void (*CGDataProviderReleaseDataCallback)(void *info, const void *data, size_t size); In this case, you could supply a retained object in info, then release it in the callback (after appropriate casting). How would I do this in Swift?
With assistance from Quinn 'The Eskimo' at Apple I found out how to do this. Given an object: let pixelBuffer: CVPixelBuffer get a pointer: Get an unmanaged object after retaining it: let fooU: Unmanaged = Unmanaged.passRetained(pixelBuffer) Convert it to a raw pointer let foo: UnsafeMutableRawPointer = fooU.toOpaque() Recover the object while releasing it: Convert the raw pointer to an unmanaged typed object let ptr: Unmanaged<CVPixelBuffer> = Unmanaged.fromOpaque(pixelPtr) Recover the actual object while releasing it let pixelBuffer: CVPixelBuffer = ptr.takeRetainedValue() The following code has been tested in an app. Note without Apple's help I'd never have figured this out thus the Q & A! Hope it helps someone! Also, note the use of #convention(c), something I'd never seen before! let fooU: Unmanaged = Unmanaged.passRetained(pixelBuffer) let foo: UnsafeMutableRawPointer = fooU.toOpaque() /* Either "bar" works */ /* let bar: #convention(c) (UnsafeMutableRawPointer?, UnsafeRawPointer, Int) -> Swift.Void = { */ let bar: CGDataProviderReleaseDataCallback = { (_ pixelPtr: UnsafeMutableRawPointer?, _ data: UnsafeRawPointer, _ size: Int) in if let pixelPtr = pixelPtr { let ptr: Unmanaged<CVPixelBuffer> = Unmanaged.fromOpaque(pixelPtr) let pixelBuffer: CVPixelBuffer = ptr.takeRetainedValue() CVPixelBufferUnlockBaseAddress(pixelBuffer, CVPixelBufferLockFlags(rawValue: 0)) DispatchQueue.main.async { print("UNLOCKED IT!") } } } let val: CVReturn = CVPixelBufferLockBaseAddress(pixelBuffer, CVPixelBufferLockFlags(rawValue: 0)) if val == kCVReturnSuccess, let sourceBaseAddr = CVPixelBufferGetBaseAddress(pixelBuffer), let provider = CGDataProvider(dataInfo: foo, data: sourceBaseAddr, size: sourceRowBytes * height, releaseData: bar) { let colorspace = CGColorSpaceCreateDeviceRGB() let image = CGImage(width: width, height: height, bitsPerComponent: 8, bitsPerPixel: 32, bytesPerRow: sourceRowBytes, space: colorspace, bitmapInfo: bitmapInfo, provider: provider, decode: nil, shouldInterpolate: true, intent: CGColorRenderingIntent.defaultIntent) /* CVPixelBufferUnlockBaseAddress(pixelBuffer, CVPixelBufferLockFlags(rawValue: 0)) */ return image } else { return nil } Quinn recently updated the Apple Forum thread on this, stating that somehow this technique never made it into either of the two Apple Swift Documents, and that he just entered a rdar to get it added. So you won't find this info anywhere else (well, at least now!)
Swift thinks my string is an MDL material
I'm trying to save data in an image metadata in iOS/Swift3. It does not appear that CG will let you save out custom tags (is that true?) so I JSON encoded my dictionary and put the result as a string into the TIFF tag's ImageDescription. When I load the image and get the metadata back... if let data = NSData(contentsOfFile:oneURL.path), let imgSrc = CGImageSourceCreateWithData(data, options as CFDictionary) { let allmeta = CGImageSourceCopyPropertiesAtIndex(imgSrc, 0, options as CFDictionary) as? [String : AnyObject] The allMeta contains (among other things): ▿ 0 : 2 elements - key : ImageDescription - value : { "CameraOrientationW" : 0.1061191, "CameraOrientationZ" : -0.01305595, "CameraOrientationX" : 0.01319851, "CameraOrientationY" : 0.9941801 } Which has the JSON data, yay! So now I simply have to get the TIFF metadata, get the ImageDescription from that, and de-JSON it... let tiffmeta = allmeta?["{TIFF}"] if let tiffMeta = tiffmeta { let descmeta = tiffMeta["ImageDescription"] var descdata = descmeta?.data(usingEncoding: NSUTF8StringEncoding)! let descdict = try? JSONSerialization.jsonObject(with: descdata, options: []) But this will not compile. Xcode puts an error on the let descdata line: Value of type 'MDLMaterialProperty??' has no member 'data' I tried casting it to String on the line above, at which point it complains I didn't unwrap the optional MDLMaterialProperty. Am I missing something obvious here?
So just to close this one, this appears to be a problem in the compiler. I made a number of minor changes to the syntax, nothing that had any actual effect on the code, and suddenly it decided the object was indeed a string.