Last active
July 19, 2017 08:18
-
-
Save sunwayforever/4861c332c43d917da45a22b4bab47ab0 to your computer and use it in GitHub Desktop.
wbxml converter
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
#include <WbXmlConverter.hpp> | |
#include <utils/String8.h> | |
using namespace android; | |
const char* WbXmlConverter::DRM_ELEMENT_CODE_PAGE[] = { | |
RO_ELEMENT_RIGHTS, RO_ELEMENT_CONTEXT, RO_ELEMENT_VERSION, RO_ELEMENT_UID, RO_ELEMENT_AGREEMENT, | |
RO_ELEMENT_ASSET, RO_ELEMENT_KEYINFO, RO_ELEMENT_KEYVALUE, RO_ELEMENT_PERMISSION, RO_ELEMENT_PLAY, | |
RO_ELEMENT_DISPLAY, RO_ELEMENT_EXECUTE, RO_ELEMENT_PRINT, RO_ELEMENT_CONSTRAINT, RO_ELEMENT_COUNT, | |
RO_ELEMENT_DATE_TIME, RO_ELEMENT_START_TIME, RO_ELEMENT_EXPIRY_TIME, RO_ELEMENT_AVAILABLE_TIME | |
}; | |
WbXmlConverter::WbXmlConverter(char* buffer, int length) | |
:length(length), position(0), state(EXPECT_HEADER) | |
{ | |
this->buffer = (char*)malloc(length); | |
memcpy(this->buffer, buffer, length); | |
} | |
WbXmlConverter::~WbXmlConverter() { | |
if (buffer) { | |
free(buffer); | |
buffer = NULL; | |
} | |
} | |
int WbXmlConverter::peekByte() { | |
int ret = 0; | |
memcpy(&ret, buffer+position, 1); | |
return ret; | |
} | |
int WbXmlConverter::read(char* outBuffer, int size) { | |
if (position >= length) { | |
return 0; | |
} | |
if (position+size < length) { | |
memcpy(outBuffer, buffer+position, size); | |
position += size; | |
return size; | |
} else { | |
memcpy(outBuffer, buffer+position, length-position); | |
position = length; | |
return length-position; | |
} | |
} | |
int WbXmlConverter::readByte() { | |
int ret = 0; | |
read((char*)&ret, 1); | |
return ret; | |
} | |
int WbXmlConverter::readUint32() { | |
int ret = 0; | |
char uintFragment=0; | |
while (true) { | |
read(&uintFragment,1); | |
ret = (ret << 7) + (uintFragment & 0x7f); | |
if ((uintFragment & (1<<7)) == 0) { | |
break; | |
} | |
} | |
return ret; | |
} | |
char* WbXmlConverter::convert() { | |
String8 ret; | |
Vector<char*> tagStack; | |
String8 pendingText; | |
while (true) { | |
switch (state) { | |
case EXPECT_HEADER: | |
{ | |
// read header, public id, strtbl | |
// version | |
int version = readByte(); | |
SUNWAY_NOISY(ALOGE("WbXmlConverter::version:%d",version)); | |
// public id | |
int publicId = readUint32(); | |
SUNWAY_NOISY(ALOGE("WbXmlConverter::public id:%d",publicId)); | |
if (publicId == 0) { | |
int idnex = readUint32(); | |
SUNWAY_NOISY(ALOGE("WbXmlConverter::public id is 0, str index:%d",index)); | |
} | |
// charset | |
int charset = readUint32(); | |
SUNWAY_NOISY(ALOGE("WbXmlConverter::charset:%d",charset)); | |
// strtbl | |
int length = readUint32(); | |
SUNWAY_NOISY(ALOGE("WbXmlConverter::strtbl size:%d",length)); | |
if (length != 0) { | |
char buffer [length]; | |
bzero(buffer, length); | |
read(buffer, length); | |
int prevousIndex = 0; | |
for (int i=0; i<length; ++i) { | |
char tmp = buffer[i]; | |
if (tmp == NULL) { | |
SUNWAY_NOISY(ALOGE("WbXmlConverter::get strbtl entry: %s",buffer+prevousIndex)); | |
strtbl.push(String8(buffer+prevousIndex)); | |
prevousIndex = i+1; | |
} | |
} | |
} | |
state = EXPECT_ELEMENT_START; | |
break; | |
} | |
case EXPECT_ELEMENT_START: | |
{ | |
int stag = readByte(); | |
char * name = NULL; | |
if ((stag & 0x3f) == TOKEN_LITERAL) { | |
name = (char*)strtbl.itemAt(readUint32()).string(); | |
} else { | |
name = lookupTagName(stag); | |
} | |
Vector<Pair> attributes; | |
// have attributes | |
if (stag & 0x80) { | |
while (readByte() != TOKEN_END) { | |
// FIXME skip attributes | |
} | |
} | |
startElement(ret, name, attributes); | |
if (stag & 0x40) { | |
state = EXPECT_CONTENT; | |
} else { | |
state = ELEMENT_END; | |
} | |
tagStack.push(name); | |
break; | |
} | |
case EXPECT_CONTENT: | |
{ | |
int byte = peekByte(); | |
if (isTagStart(byte) || byte == TOKEN_END) { | |
if (pendingText.size()) { | |
onText(ret, (char*)pendingText.string()); | |
pendingText.clear(); | |
} | |
if (byte == TOKEN_END) { | |
state = EXPECT_ELEMENT_END; | |
} else { | |
state = EXPECT_ELEMENT_START; | |
} | |
} else if (byte == TOKEN_OPAQUE) { | |
// skip TOKEN_OPAQUE | |
readByte(); | |
int length = readUint32(); | |
char opaqueData[length]; | |
bzero(opaqueData, length); | |
read(opaqueData, length); | |
onOpaque(ret, opaqueData, length); | |
} else if (byte == TOKEN_ENTITY || byte == TOKEN_STR_I || byte == TOKEN_STR_T) { | |
pendingText.append(readString()); | |
} | |
break; | |
} | |
case EXPECT_ELEMENT_END: | |
{ | |
// must be end token | |
readByte(); | |
char* tagName = tagStack.top(); | |
tagStack.pop(); | |
endElement(ret, tagName); | |
if (tagStack.empty()) { | |
state = EXPECT_BODY_END; | |
} else { | |
state = EXPECT_CONTENT; | |
} | |
break; | |
} | |
case EXPECT_BODY_END: | |
{ | |
SUNWAY_NOISY(ALOGE("WbXmlConverter:: result: %s", ret.string())); | |
return strdup(ret.string()); | |
} | |
} | |
} | |
} | |
// not used yet | |
Pair WbXmlConverter::readAttribute() { | |
Pair ret; | |
int attrStart = readByte(); | |
char * name = NULL; | |
char * valuePrefix = NULL; | |
if (attrStart == TOKEN_LITERAL) { | |
name = (char*)strtbl.itemAt(readUint32()).string(); | |
} else { | |
name = lookupAttrName(attrStart, &valuePrefix); | |
} | |
ret.name = name; | |
ret.value = ""; | |
if (valuePrefix != NULL) { | |
ret.value = valuePrefix; | |
} | |
for (;;) { | |
int valueToken = peekByte(); | |
if (isAttrStart(valueToken) || valueToken == TOKEN_END) { | |
// An attribute start token, a LITERAL token or the END token | |
// indicates the end of an attribute value. | |
return ret; | |
} | |
if (isAttrValue(valueToken)) { | |
String8 tmp (ret.value); | |
tmp.append(lookupAttrValue(valueToken)); | |
ret.value = (char*)tmp.string(); | |
} else if (valueToken == TOKEN_ENTITY || valueToken == TOKEN_STR_I || valueToken == TOKEN_STR_T) { | |
String8 tmp (ret.value); | |
tmp.append(readString()); | |
ret.value = (char*)tmp.string(); | |
} else { | |
ret.value = "unknown"; | |
return ret; | |
} | |
} | |
} | |
char* WbXmlConverter::lookupTagName(int stag) { | |
int realStag = stag & 0x3f; | |
return (char*)DRM_ELEMENT_CODE_PAGE[realStag - WBXML_EXT_OFFSET]; | |
} | |
char* WbXmlConverter::lookupAttrValue(int valueToken) { | |
return "attr_value"; | |
} | |
char* WbXmlConverter::lookupAttrName(int start, char** prefix) { | |
*prefix = NULL; | |
return "attr_name"; | |
} | |
bool WbXmlConverter::isTagStart(int token) { | |
token &= 0x3f; | |
return (token >= TOKEN_LITERAL && token < TOKEN_EXT_I_0); | |
} | |
bool WbXmlConverter::isAttrStart(int token) { | |
return (token >= TOKEN_LITERAL && token < TOKEN_EXT_I_0) || | |
(token > TOKEN_LITERAL_C && token < 0x80); | |
} | |
bool WbXmlConverter::isAttrValue(int token) { | |
return (token > TOKEN_LITERAL_A && token < 0xC0); | |
} | |
char* WbXmlConverter::readString() | |
{ | |
String8 ret; | |
int byte = readByte(); | |
switch (byte) { | |
case TOKEN_STR_I: | |
//TODO: assuming UTF-8 | |
while ((byte = readByte()) != 0) { | |
ret.appendFormat("%c", byte); | |
} | |
break; | |
case TOKEN_ENTITY: | |
{ | |
int ch = readUint32(); | |
if (ch <= 0x7f) { | |
ret.appendFormat("%c",(char)ch); | |
} else if (ch <= 0x7ff) { | |
ret.appendFormat("%c%c",(char)((ch >> 6) | 0xc0),(char)((ch & 0x3f) | 0x80)); | |
} else if (ch <= 0xffff) { | |
ret.appendFormat("%c%c%c",(char)((ch >> 12) | 0xe0),(char)(((ch >> 6) & 0x3f) | 0x80),(char)((ch & 0x3f) | 0x80)); | |
} else if (ch <= 0x10ffff) { | |
// 010000 - 10FFFF | |
ret.appendFormat("%c%c%c%c",(char)((ch >> 18) | 0xf0),(char)(((ch >> 12) & 0x3f) | 0x80),(char)(((ch >> 6) & 0x3f) | 0x80),(char)((ch & 0x3f) | 0x80)); | |
} else { | |
// not a valid UCS-4 character | |
} | |
break; | |
} | |
case TOKEN_STR_T: | |
{ | |
ret = String8(strtbl.itemAt(readUint32())); | |
break; | |
} | |
default: | |
// impossible | |
printf ("Unknown token 0x%02x\n", byte); | |
break; | |
} | |
return (char*)ret.string(); | |
} | |
void WbXmlConverter::startElement(String8& out, char* name, Vector<Pair> attributes) { | |
SUNWAY_NOISY(ALOGE("WbXmlConverter:: startElement: %s", name)); | |
out.appendFormat("<%s>", name); | |
} | |
void WbXmlConverter::endElement(String8& out, char* name) { | |
SUNWAY_NOISY(ALOGE("WbXmlConverter:: endElement: %s", name)); | |
out.appendFormat("</%s>", name); | |
} | |
void WbXmlConverter::onText(String8& out, char* text) { | |
SUNWAY_NOISY(ALOGE("WbXmlConverter:: onText: %s", text)); | |
out.appendFormat("%s",text); | |
} | |
void WbXmlConverter::onOpaque(String8& out, char* buffer, int length) { | |
SUNWAY_NOISY(ALOGE("WbXmlConverter:: onOpaque: %d", length)); | |
char* tmp = base64(buffer, length); | |
out.appendFormat("%s", tmp); | |
free(tmp); | |
} |
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
#ifndef WB_XML_CONVERTER_HPP | |
#define WB_XML_CONVERTER_HPP | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <setjmp.h> | |
#include <assert.h> | |
#include <common.hpp> | |
#include <utils/Vector.h> | |
#include <utils/String8.h> | |
#define TOKEN_SWITCH_PAGE 0x0 | |
#define TOKEN_END 0x1 | |
#define TOKEN_ENTITY 0x2 | |
#define TOKEN_STR_I 0x3 | |
#define TOKEN_LITERAL 0x4 | |
#define TOKEN_EXT_I_0 0x40 | |
#define TOKEN_EXT_I_1 0x41 | |
#define TOKEN_EXT_I_2 0x42 | |
#define TOKEN_PI 0x43 | |
#define TOKEN_LITERAL_C 0x44 | |
#define TOKEN_EXT_T_0 0x80 | |
#define TOKEN_EXT_T_1 0x81 | |
#define TOKEN_EXT_T_2 0x82 | |
#define TOKEN_STR_T 0x83 | |
#define TOKEN_LITERAL_A 0x84 | |
#define TOKEN_EXT_0 0xc0 | |
#define TOKEN_EXT_1 0xc1 | |
#define TOKEN_EXT_2 0xc2 | |
#define TOKEN_OPAQUE 0xc3 | |
#define TOKEN_LITERAL_AC 0xc4 | |
#define WBXML_EXT_OFFSET 5 | |
// for test | |
#define CARD 6 | |
#define BR 5 | |
#define XYZ 7 | |
namespace android { | |
struct Pair { | |
char* name; | |
char* value; | |
}; | |
class WbXmlConverter { | |
private: | |
static const char* DRM_ELEMENT_CODE_PAGE[19]; | |
enum ParserState { | |
EXPECT_HEADER, | |
EXPECT_ELEMENT_START, | |
EXPECT_ELEMENT_END, | |
ELEMENT_END, | |
EXPECT_CONTENT, | |
EXPECT_BODY_END, | |
}; | |
ParserState state; | |
char* buffer; | |
int length; | |
int position; | |
Vector<String8> strtbl; | |
int readByte(); | |
int peekByte(); | |
int readUint32(); | |
char* readString(); | |
Pair readAttribute(); | |
int read(char* buffer, int size); | |
char* lookupTagName(int stag); | |
char* lookupAttrName(int start, char** prefix); | |
char* lookupAttrValue(int start); | |
void startElement(String8& out, char* name, Vector<Pair> attributes); | |
void endElement(String8& out, char* name); | |
void onText(String8& out, char* name); | |
void onOpaque(String8& out, char* buffer, int length); | |
static bool isTagStart(int token); | |
static bool isAttrStart(int token); | |
static bool isAttrValue(int token); | |
public: | |
WbXmlConverter(char* buffer, int length); | |
virtual ~WbXmlConverter(); | |
char* convert(); | |
}; | |
}; | |
#endif // WB_XML_CONVERTER_HPP |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment