-
Notifications
You must be signed in to change notification settings - Fork 41
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #177 from NordicSemiconductor/bugfix/canonical-cbor
Fixed encoding CBOR in canonical format
- Loading branch information
Showing
4 changed files
with
140 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
53 changes: 53 additions & 0 deletions
53
mcumgr-core/src/main/java/io/runtime/mcumgr/util/CanonicalCBORFactory.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
package io.runtime.mcumgr.util; | ||
|
||
import com.fasterxml.jackson.core.JsonEncoding; | ||
import com.fasterxml.jackson.core.ObjectCodec; | ||
import com.fasterxml.jackson.core.io.IOContext; | ||
import com.fasterxml.jackson.dataformat.cbor.CBORConstants; | ||
import com.fasterxml.jackson.dataformat.cbor.CBORFactory; | ||
import com.fasterxml.jackson.dataformat.cbor.CBORGenerator; | ||
|
||
import java.io.IOException; | ||
import java.io.OutputStream; | ||
|
||
/** | ||
* This class is a copy of {@link CBORFactory} with the only difference | ||
* that it returns {@link CanonicalCBORGenerator} instead of {@link CBORGenerator}. | ||
*/ | ||
public class CanonicalCBORFactory extends CBORFactory { | ||
|
||
@Override | ||
public CBORGenerator createGenerator(OutputStream out, JsonEncoding enc) throws IOException { | ||
final IOContext ctxt = _createContext(_createContentReference(out), false); | ||
return _createCBORGenerator(ctxt, | ||
_generatorFeatures, _formatGeneratorFeatures, _objectCodec, | ||
_decorate(out, ctxt)); | ||
} | ||
|
||
@Override | ||
public CBORGenerator createGenerator(OutputStream out) throws IOException { | ||
final IOContext ctxt = _createContext(_createContentReference(out), false); | ||
return _createCBORGenerator(ctxt, | ||
_generatorFeatures, _formatGeneratorFeatures, _objectCodec, | ||
_decorate(out, ctxt)); | ||
} | ||
|
||
@Override | ||
protected CBORGenerator _createUTF8Generator(OutputStream out, IOContext ctxt) throws IOException { | ||
return _createCBORGenerator(ctxt, | ||
_generatorFeatures, _formatGeneratorFeatures, _objectCodec, out); | ||
} | ||
|
||
// These methods are required to make the overriding class to work: | ||
|
||
private CBORGenerator _createCBORGenerator(IOContext ctxt, | ||
int stdFeat, int formatFeat, ObjectCodec codec, OutputStream out) throws IOException | ||
{ | ||
// false -> we won't manage the stream unless explicitly directed to | ||
CanonicalCBORGenerator gen = new CanonicalCBORGenerator(ctxt, stdFeat, formatFeat, _objectCodec, out); | ||
if (CBORGenerator.Feature.WRITE_TYPE_HEADER.enabledIn(formatFeat)) { | ||
gen.writeTag(CBORConstants.TAG_ID_SELF_DESCRIBE); | ||
} | ||
return gen; | ||
} | ||
} |
83 changes: 83 additions & 0 deletions
83
mcumgr-core/src/main/java/io/runtime/mcumgr/util/CanonicalCBORGenerator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
package io.runtime.mcumgr.util; | ||
|
||
import static com.fasterxml.jackson.dataformat.cbor.CBORConstants.PREFIX_TYPE_OBJECT; | ||
import static com.fasterxml.jackson.dataformat.cbor.CBORConstants.SUFFIX_UINT16_ELEMENTS; | ||
import static com.fasterxml.jackson.dataformat.cbor.CBORConstants.SUFFIX_UINT32_ELEMENTS; | ||
import static com.fasterxml.jackson.dataformat.cbor.CBORConstants.SUFFIX_UINT8_ELEMENTS; | ||
|
||
import com.fasterxml.jackson.core.ObjectCodec; | ||
import com.fasterxml.jackson.core.io.IOContext; | ||
import com.fasterxml.jackson.dataformat.cbor.CBORGenerator; | ||
|
||
import java.io.IOException; | ||
import java.io.OutputStream; | ||
import java.util.Arrays; | ||
|
||
/** | ||
* This class is a copy of {@link CBORGenerator} with the only difference | ||
* that it writes maps in canonical form. | ||
* <p> | ||
* The implementation is copied from {@link CBORGenerator} at version 2.17.1, which cannot be used | ||
* as 2.14+ support only Android 8+. | ||
*/ | ||
public class CanonicalCBORGenerator extends CBORGenerator { | ||
|
||
public CanonicalCBORGenerator(IOContext ctxt, int stdFeatures, int formatFeatures, ObjectCodec codec, OutputStream out) { | ||
super(ctxt, stdFeatures, formatFeatures, codec, out); | ||
} | ||
|
||
public CanonicalCBORGenerator(IOContext ctxt, int stdFeatures, int formatFeatures, ObjectCodec codec, OutputStream out, byte[] outputBuffer, int offset, boolean bufferRecyclable) { | ||
super(ctxt, stdFeatures, formatFeatures, codec, out, outputBuffer, offset, bufferRecyclable); | ||
} | ||
|
||
@Override | ||
public void writeStartObject(Object forValue, int elementsToWrite) throws IOException { | ||
_verifyValueWrite("start an object"); | ||
_streamWriteContext = _streamWriteContext.createChildObjectContext(forValue); | ||
_pushRemainingElements(); | ||
_currentRemainingElements = elementsToWrite; | ||
_writeLengthMarker(PREFIX_TYPE_OBJECT, elementsToWrite); | ||
} | ||
|
||
// These methods are required to make the overriding class to work: | ||
|
||
private void _pushRemainingElements() { | ||
if (_elementCounts.length == _elementCountsPtr) { // initially, as well as if full | ||
_elementCounts = Arrays.copyOf(_elementCounts, _elementCounts.length+10); | ||
} | ||
_elementCounts[_elementCountsPtr++] = _currentRemainingElements; | ||
} | ||
|
||
private void _writeLengthMarker(int majorType, int i) | ||
throws IOException { | ||
_ensureRoomForOutput(5); | ||
if (i < 24) { | ||
_outputBuffer[_outputTail++] = (byte) (majorType + i); | ||
return; | ||
} | ||
if (i <= 0xFF) { | ||
_outputBuffer[_outputTail++] = (byte) (majorType + SUFFIX_UINT8_ELEMENTS); | ||
_outputBuffer[_outputTail++] = (byte) i; | ||
return; | ||
} | ||
final byte b0 = (byte) i; | ||
i >>= 8; | ||
if (i <= 0xFF) { | ||
_outputBuffer[_outputTail++] = (byte) (majorType + SUFFIX_UINT16_ELEMENTS); | ||
_outputBuffer[_outputTail++] = (byte) i; | ||
_outputBuffer[_outputTail++] = b0; | ||
return; | ||
} | ||
_outputBuffer[_outputTail++] = (byte) (majorType + SUFFIX_UINT32_ELEMENTS); | ||
_outputBuffer[_outputTail++] = (byte) (i >> 16); | ||
_outputBuffer[_outputTail++] = (byte) (i >> 8); | ||
_outputBuffer[_outputTail++] = (byte) i; | ||
_outputBuffer[_outputTail++] = b0; | ||
} | ||
|
||
private void _ensureRoomForOutput(int needed) throws IOException { | ||
if ((_outputTail + needed) >= _outputEnd) { | ||
_flushBuffer(); | ||
} | ||
} | ||
} |