编译后的AndroidManifest.xml查看及修改源码
编译后的AndroidManifest.xml查看及修改源码
还在编写中,用于在无需其他文件的情况下,单独修改编译后的二进制AndroidManifest.xml文件,目前应该是全网首创吧
#pragma once
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned long uint32_t;
#include <vector>
#include <stack>
#include <string>
using namespace std;
enum {
RES_NULL_TYPE = 0x0000,
RES_STRING_POOL_TYPE = 0x0001,
RES_TABLE_TYPE = 0x0002,
RES_XML_TYPE = 0x0003,
// Chunk types in RES_XML_TYPE
RES_XML_FIRST_CHUNK_TYPE = 0x0100,
RES_XML_START_NAMESPACE_TYPE = 0x0100,
RES_XML_END_NAMESPACE_TYPE = 0x0101,
RES_XML_START_ELEMENT_TYPE = 0x0102,
RES_XML_END_ELEMENT_TYPE = 0x0103,
RES_XML_CDATA_TYPE = 0x0104,
RES_XML_LAST_CHUNK_TYPE = 0x017f,
// This contains a uint32_t array mapping strings in the string
// pool back to resource identifiers.It is optional.
RES_XML_RESOURCE_MAP_TYPE = 0x0180,
// Chunk types in RES_TABLE_TYPE
RES_TABLE_PACKAGE_TYPE = 0x0200,
RES_TABLE_TYPE_TYPE = 0x0201,
RES_TABLE_TYPE_SPEC_TYPE = 0x0202
};
struct Res_value
{
// Number of bytes in this structure.
uint16_t size;
// Always set to 0.
uint8_t res0;
// Type of the data value.
enum {
// The 'data' is either 0 or 1, specifying this resource is either
// undefined or empty, respectively.
TYPE_NULL = 0x00,
// The 'data' holds a ResTable_ref, a reference to another resource
// table entry.
TYPE_REFERENCE = 0x01,
// The 'data' holds an attribute resource identifier.
TYPE_ATTRIBUTE = 0x02,
// The 'data' holds an index into the containing resource table's
// global value string pool.
TYPE_STRING = 0x03,
// The 'data' holds a single-precision floating point number.
TYPE_FLOAT = 0x04,
// The 'data' holds a complex number encoding a dimension value,
// such as "100in".
TYPE_DIMENSION = 0x05,
// The 'data' holds a complex number encoding a fraction of a
// container.
TYPE_FRACTION = 0x06,
// The 'data' holds a dynamic ResTable_ref, which needs to be
// resolved before it can be used like a TYPE_REFERENCE.
TYPE_DYNAMIC_REFERENCE = 0x07,
// Beginning of integer flavors...
TYPE_FIRST_INT = 0x10,
// The 'data' is a raw integer value of the form n..n.
TYPE_INT_DEC = 0x10,
// The 'data' is a raw integer value of the form 0xn..n.
TYPE_INT_HEX = 0x11,
// The 'data' is either 0 or 1, for input "false" or "true" respectively.
TYPE_INT_BOOLEAN = 0x12,
// Beginning of color integer flavors...
TYPE_FIRST_COLOR_INT = 0x1c,
// The 'data' is a raw integer value of the form #aarrggbb.
TYPE_INT_COLOR_ARGB8 = 0x1c,
// The 'data' is a raw integer value of the form #rrggbb.
TYPE_INT_COLOR_RGB8 = 0x1d,
// The 'data' is a raw integer value of the form #argb.
TYPE_INT_COLOR_ARGB4 = 0x1e,
// The 'data' is a raw integer value of the form #rgb.
TYPE_INT_COLOR_RGB4 = 0x1f,
// ...end of integer flavors.
TYPE_LAST_COLOR_INT = 0x1f,
// ...end of integer flavors.
TYPE_LAST_INT = 0x1f
};
uint8_t dataType;
// Structure of complex data values (TYPE_UNIT and TYPE_FRACTION)
enum {
// Where the unit type information is.This gives us 16 possible
// types, as defined below.
COMPLEX_UNIT_SHIFT = 0,
COMPLEX_UNIT_MASK = 0xf,
// TYPE_DIMENSION: Value is raw pixels.
COMPLEX_UNIT_PX = 0,
// TYPE_DIMENSION: Value is Device Independent Pixels.
COMPLEX_UNIT_DIP = 1,
// TYPE_DIMENSION: Value is a Scaled device independent Pixels.
COMPLEX_UNIT_SP = 2,
// TYPE_DIMENSION: Value is in points.
COMPLEX_UNIT_PT = 3,
// TYPE_DIMENSION: Value is in inches.
COMPLEX_UNIT_IN = 4,
// TYPE_DIMENSION: Value is in millimeters.
COMPLEX_UNIT_MM = 5,
// TYPE_FRACTION: A basic fraction of the overall size.
COMPLEX_UNIT_FRACTION = 0,
// TYPE_FRACTION: A fraction of the parent size.
COMPLEX_UNIT_FRACTION_PARENT = 1,
// Where the radix information is, telling where the decimal place
// appears in the mantissa.This give us 4 possible fixed point
// representations as defined below.
COMPLEX_RADIX_SHIFT = 4,
COMPLEX_RADIX_MASK = 0x3,
// The mantissa is an integral number -- i.e., 0xnnnnnn.0
COMPLEX_RADIX_23p0 = 0,
// The mantissa magnitude is 16 bits -- i.e, 0xnnnn.nn
COMPLEX_RADIX_16p7 = 1,
// The mantissa magnitude is 8 bits -- i.e, 0xnn.nnnn
COMPLEX_RADIX_8p15 = 2,
// The mantissa magnitude is 0 bits -- i.e, 0x0.nnnnnn
COMPLEX_RADIX_0p23 = 3,
// Where the actual value is.This gives us 23 bits of
// precision.The top bit is the sign.
COMPLEX_MANTISSA_SHIFT = 8,
COMPLEX_MANTISSA_MASK = 0xffffff
};
// Possible data values for TYPE_NULL.
enum {
// The value is not defined.
DATA_NULL_UNDEFINED = 0,
// The value is explicitly defined as empty.
DATA_NULL_EMPTY = 1
};
// The data for this item, as interpreted according to dataType.
typedef uint32_t data_type;
data_type data;
};
struct ResChunk_header
{
// Type identifier for this chunk.The meaning of this value depends
// on the containing chunk.
uint16_t type;
// Size of the chunk header (in bytes).Adding this value to
// the address of the chunk allows you to find its associated data
// (if any).
uint16_t headerSize;
// Total size of this chunk (in bytes).This is the chunkSize plus
// the size of any data associated with the chunk.Adding this value
// to the chunk allows you to completely skip its contents (including
// any child chunks).If this value is the same as chunkSize, there is
// no data associated with the chunk.
uint32_t size;
};
struct ResStringPool_header
{
struct ResChunk_header header;
// Number of strings in this pool (number of uint32_t indices that follow
// in the data).
uint32_t stringCount;
// Number of style span arrays in the pool (number of uint32_t indices
// follow the string indices).
uint32_t styleCount;
// Flags.
enum {
// If set, the string index is sorted by the string values (based
// on strcmp16()).
SORTED_FLAG = 1<<0,
// String pool is encoded in UTF-8
UTF8_FLAG = 1<<8
};
uint32_t flags;
// Index from header of the string data.
uint32_t stringsStart;
// Index from header of the style data.
uint32_t stylesStart;
};
/**
* Reference to a string in a string pool.
*/
struct ResStringPool_ref
{
// Index into the string pool table (uint32_t-offset from the indices
// immediately after ResStringPool_header) at which to find the location
// of the string data in the pool.
uint32_t index;
};
/**
* Extended XML tree node for namespace start/end nodes.
* Appears header.headerSize bytes after a ResXMLTree_node.
*/
struct ResXMLTree_namespaceExt
{
// The prefix of the namespace.
struct ResStringPool_ref prefix;
// The URI of the namespace.
struct ResStringPool_ref uri;
};
/**
* Extended XML tree node for element start/end nodes.
* Appears header.headerSize bytes after a ResXMLTree_node.
*/
struct ResXMLTree_endElementExt
{
// String of the full namespace of this element.
struct ResStringPool_ref ns;
// String name of this node if it is an ELEMENT; the raw
// character data if this is a CDATA node.
struct ResStringPool_ref name;
};
/**
* Extended XML tree node for element start/end nodes.
* Appears header.headerSize bytes after a ResXMLTree_node.
*/
struct ResXMLTree_endElementExt
{
// String of the full namespace of this element.
struct ResStringPool_ref ns;
// String name of this node if it is an ELEMENT; the raw
// character data if this is a CDATA node.
struct ResStringPool_ref name;
};
/**
* Extended XML tree node for start tags -- includes attribute
* information.
* Appears header.headerSize bytes after a ResXMLTree_node.
*/
struct ResXMLTree_attrExt
{
// String of the full namespace of this element.
struct ResStringPool_ref ns;
// String name of this node if it is an ELEMENT; the raw
// character data if this is a CDATA node.
struct ResStringPool_ref name;
// Byte offset from the start of this structure where the attributes start.
uint16_t attributeStart;
// Size of the ResXMLTree_attribute structures that follow.
uint16_t attributeSize;
// Number of attributes associated with an ELEMENT.These are
// available as an array of ResXMLTree_attribute structures
// immediately following this node.
uint16_t attributeCount;
// Index (1-based) of the "id" attribute. 0 if none.
uint16_t idIndex;
// Index (1-based) of the "class" attribute. 0 if none.
uint16_t classIndex;
// Index (1-based) of the "style" attribute. 0 if none.
uint16_t styleIndex;
};
struct ResXMLTree_attribute
{
// Namespace of this attribute.
struct ResStringPool_ref ns;
// Name of this attribute.
struct ResStringPool_ref name;
// The original raw string value of this attribute.
struct ResStringPool_ref rawValue;
// Processesd typed value of this attribute.
struct Res_value typedValue;
};
//RES_STRING_POOL_TYPE
class ResStringPool
{
public:
struct ResStringPool_header header;
std::vector<int> stringOffsets;
std::vector<int> styleOffsets;
std::vector<unsigned char> stringData;
std::vector<unsigned char> styleData;
void setTo(unsigned char* nodeData)
{
header = *(struct ResStringPool_header*)nodeData;
int i=0;
unsigned char* offset;
offset = nodeData + sizeof(struct ResStringPool_header);
for(i=0;i<header.stringCount;i++)
{
stringOffsets.push_back(*(int*)offset);
offset += 4;
}
for(i=0;i<header.styleCount;i++)
{
styleOffsets.push_back(*(int*)offset);
offset += 4;
}
if(header.stringCount == 0 && header.styleCount != 0)
{
styleData.resize(header.header.size - header.stylesStart);
styleData.assign(nodeData + header.stylesStart,nodeData + header.header.size);
}
else if(header.stringCount != 0 && header.styleCount == 0)
{
stringData.resize(header.header.size - header.stringsStart);
stringData.assign(nodeData + header.stringsStart,nodeData + header.header.size);
}
else if(header.stringCount != 0 && header.styleCount != 0)
{
if(header.stringsStart < header.stylesStart)
{//stringsStart < stylesStart < end
stringData.assign(header.stylesStart - header.stringsStart);
styleData.assign(header.header.size - header.stylesStart);
stringData.assign(nodeData + header.stringsStart, nodeData + header.stylesStart);
styleData.assign(nodeData + header.stylesStart, nodeData + header.header.size);
}
else
{//stylesStart < stringsStart < end
stringData.assign(header.stringsStart - header.stylesStart);
styleData.assign(header.header.size - header.stringsStart);
styleData.assign(nodeData + header.stylesStart, nodeData + header.stringsStart);
stringData.assign(nodeData + header.stringsStart, nodeData + header.header.size);
}
}
}
void serialize(unsigned char* nodeData, int& size)
{//调整参数使结构都是紧密排列的
header.stringsStart = sizeof(struct ResStringPool_header) + stringOffsets.size()*4 + styleOffsets.size()*4;
header.stylesStart = sizeof(struct ResStringPool_header) + stringOffsets.size()*4 + styleOffsets.size()*4 + stringData.size();
int realsize = getSize();
if(size < realsize)
size=0;
size = realsize;
int offset = 0;
memcpy(nodeData + offset, &header, sizeof(struct ResStringPool_header));
offset += sizeof(struct ResStringPool_header);
memcpy(nodeData + offset, &stringOffsets, stringOffsets.size()*4);
offset += stringOffsets.size()*4;
memcpy(nodeData + offset, &styleOffsets, styleOffsets.size()*4);
offset += styleOffsets.size()*4;
memcpy(nodeData + offset, &stringData,stringData.size());
offset += stringData.size();
memcpy(nodeData + offset, &styleData,styleData.size());
offset += styleData.size();
}
int getSize()
{
return sizeof(struct ResStringPool_header) + stringOffsets.size()*4 + styleOffsets.size()*4 + stringData.size() + styleData.size();
}
void print()
{
wprintf(L"StringPool:");
for(int i=0;i<header.stringCount;i++)
{
wprintf("%d:%s\n",(wchar_t*)(&stringData + stringOffsets + 2));
}
}
wchar_t* getItem(int index)
{
wchar_t* str = L"";
if(index >= 0 && index < header.stringCount)
{
str= (wchar_t*)(&stringData + stringOffsets + 2);
}
return str;
}
};
class ResXmlResourceMap
{
public:
struct ResChunk_header header;
std::vector<int> mapType;
void setTo(unsigned char* nodeData)
{
header = *(struct ResStringPool_header*)nodeData;
for(int i=header.headerSize;i<header.size;i+=4)
{
mapType.push_back(*(int*)(nodeData + i));
}
}
void serialize(unsigned char* nodeData, int& size)
{
int realsize = getSize();
if(size < realsize)
size=0;
size=realsize;
int offset = 0;
memcpy(nodeData + offset, &header, sizeof(ResChunk_header));
offset += sizeof(ResChunk_header);
memcpy(nodeData +offset, &mapType, mapType.size()*4);
offset += mapType.size()*4;
}
int getSize()
{
return sizeof(struct ResChunk_header) + mapType.size()*4;
}
void print()
{
wprintf(L"ResourceMap:");
for(int i=0;i<mapType.size();i++)
{
wprintf(L"%d:%08x\n",i,mapType);
}
}
int getItem(int index)
{
int ret = 0;
if(index >= 0 && index < mapType.size())
{
ret= mapType;
}
return ret;
}
};
class ResXmlTreeNode:public ResChunk_header
{
public:
int layer;//通过层号得到树形关系
struct ResXmlTreeNode* father;//知道是谁的孩子
std::wstring nodeName;
virtual void setTo(unsigned char* nodeData, ResXmlTreeNode* _father, int _layer){};
virtual void print(){};
virtual int getSize(){return sizeof(ResChunk_header)};
virtual void serialize(unsigned char* nodeData, int& size){};
};
//RES_XML_START_NAMESPACE_TYPE/RES_XML_END_NAMESPACE_TYPE
class ResXmlNamespace:public ResXmlTreeNode
{
public:
ResXMLTree_namespaceExt ext;
std::vector<unsigned char> headerData;
ResXmlNamespace(unsigned char* nodeData, ResXmlTreeNode* _father, int _layer)
{
setTo(nodeData,_father,_layer);
}
void setTo(unsigned char* nodeData, ResXmlTreeNode* _father, int _layer)
{
this->father = _father;
this->layer = _layer;
this->type = ((ResChunk_header*)nodeData)->type;
this->headerSize = ((ResChunk_header*)nodeData)->headerSize;
this->size = ((ResChunk_header*)nodeData)->size;
this->ext = *(ResXMLTree_namespaceExt*)(nodeData + this->headerSize);
headerData.resize(headerSize - sizeof(ResChunk_header));
headerData.assign(nodeData + sizeof(ResChunk_header), nodeData + this->headerSize);
}
virtual void serialize(unsigned char* nodeData, int& size)
{
int realsize = getSize();
if(size < realsize)
return;
size = realsize;
ResChunk_header header = {this->type,this->headerSize,this->size};
int offset = 0;
memcpy(nodeData + offset, &header, sizeof(ResChunk_header));
offset += sizeof(ResChunk_header);
memcpy(nodeData + offset, &headerData, headerData.size());
offset += headerData.size();
memcpy(nodeData + offset, &ext, sizeof(ResXMLTree_namespaceExt));
offset += sizeof(sizeof(ResXMLTree_namespaceExt));
}
virtual int getSize()
{
return sizeof(ResChunk_header) + sizeof(ResXMLTree_namespaceExt) + headerData.size();
}
virtual void print(ResStringPool& stringPool)
{
for(int i=0;i<layer+1;i++)
{
wprintf(L" ");
}
if(type == RES_XML_START_NAMESPACE_TYPE)
{
wprintf(L"Start Namespace %s %s\n", stringPool.getItem(ext.prefix.index), stringPool.getItem(ext.uri.index));
}
else if(type == RES_XML_END_NAMESPACE_TYPE)
{
wprintf(L"End Namespace %s %s\n", stringPool.getItem(ext.prefix.index), stringPool.getItem(ext.uri.index));
}
}
};
class ResXmlStartElement:public ResXmlTreeNode
{
ResXMLTree_attrExt ext;
std::vector<unsigned char> headerData;
std::vector<struct ResXMLTree_attribute> attribs;
ResXmlStartElement(unsigned char* nodeData, ResXmlTreeNode* _father, int _layer)
{
setTo(nodeData,_father,_layer);
}
virtual void setTo(unsigned char* nodeData, ResXmlTreeNode* _father, int _layer)
{
this->father = _father;
this->layer = _layer;
this->type = ((ResChunk_header*)nodeData)->type;
this->headerSize = ((ResChunk_header*)nodeData)->headerSize;
this->size = ((ResChunk_header*)nodeData)->size;
this->ext = *(ResXMLTree_attrExt*)(nodeData + this->headerSize);
headerData.resize(headerSize - sizeof(ResChunk_header));
headerData.assign(nodeData + sizeof(ResChunk_header), nodeData + this->headerSize);
attribs.resize(this->ext.attributeCount);
attribs.assign(*(ResXMLTree_attribute*)(nodeData + this->headerSize + this->ext.attributeStart),
*(ResXMLTree_attribute*)(nodeData + this->headerSize + this->ext.attributeStart + sizeof(struct ResXMLTree_attribute) * this->ext.attributeCount));
}
virtual void print(ResStringPool& stringPool)
{
for(int i=0;i<attribs.size();i++)
{
for(int i=0;i<layer+1;i++)
{
wprintf(L" ");
}
wprintf(L"A:%s %s %s %02x\n", stringPool.getItem(attribs.ns.index), stringPool.getItem(attribs.name.index),
stringPool.getItem(attribs.rawValue.index), attribs.typedValue.dataType);
}
}
virtual int getSize()
{
return sizeof(ResChunk_header) + headerData.size() + attribs.size() * sizeof(ResXMLTree_attribute);
}
virtual void serialize(unsigned char* nodeData, int& size)
{
int realsize = getSize();
if(size < realsize)
return;
size = realsize;
ResChunk_header header = {this->type,this->headerSize,this->size};
int offset = 0;
memcpy(nodeData + offset, &header, sizeof(ResChunk_header));
offset += sizeof(ResChunk_header);
memcpy(nodeData + offset, &headerData, headerData.size());
offset += headerData.size();
memcpy(nodeData + offset, &attribs, sizeof(ResXMLTree_attribute) * attribs.size());
offset += sizeof(ResXMLTree_attribute) * attribs.size();
}
};
class ResXmlEndElement:public ResXmlTreeNode
{
public:
ResXMLTree_endElementExt ext;
std::vector<unsigned char> headerData;
ResXmlEndElement(unsigned char* nodeData, ResXmlTreeNode* _father, int _layer)
{
setTo(nodeData,_father,_layer);
}
void setTo(unsigned char* nodeData, ResXmlTreeNode* _father, int _layer)
{
this->father = _father;
this->layer = _layer;
this->type = ((ResChunk_header*)nodeData)->type;
this->headerSize = ((ResChunk_header*)nodeData)->headerSize;
this->size = ((ResChunk_header*)nodeData)->size;
this->ext = *(ResXMLTree_endElementExt*)(nodeData + this->headerSize);
headerData.resize(headerSize - sizeof(ResChunk_header));
headerData.assign(nodeData + sizeof(ResChunk_header), nodeData + this->headerSize);
}
virtual void serialize(unsigned char* nodeData, int& size)
{
int realsize = getSize();
if(size < realsize)
return;
size = realsize;
ResChunk_header header = {this->type,this->headerSize,this->size};
int offset = 0;
memcpy(nodeData + offset, &header, sizeof(ResChunk_header));
offset += sizeof(ResChunk_header);
memcpy(nodeData + offset, &headerData, headerData.size());
offset += headerData.size();
memcpy(nodeData + offset, &ext, sizeof(ResXMLTree_endElementExt));
offset += sizeof(sizeof(ResXMLTree_endElementExt));
}
virtual int getSize()
{
return sizeof(ResChunk_header) + sizeof(ResXMLTree_endElementExt) + headerData.size();
}
virtual void print(ResStringPool& stringPool)
{
for(int i=0;i<layer+1;i++)
{
wprintf(L" ");
}
if(type == RES_XML_START_NAMESPACE_TYPE)
{
wprintf(L"Start Namespace %s %s\n", stringPool.getItem(ext.name.index), stringPool.getItem(ext.ns.index));
}
else if(type == RES_XML_END_NAMESPACE_TYPE)
{
wprintf(L"End Namespace %s %s\n", stringPool.getItem(ext.name.index), stringPool.getItem(ext.ns.index));
}
}
};
class ResXml
{
ResChunk_header header;
class ResStringPool stringPool;
class ResXmlResourceMap resourceMap;
std::vector<std::auto_ptr<class ResXmlTreeNode>> elements;
std::stack<class ResXmlTreeNode*> topstack;
void setTo(unsigned char* nodeData)
{
if(((ResChunk_header*)nodeData)->type == RES_XML_TYPE)//类型匹配
{
header = *(ResChunk_header*)nodeData;
ResChunk_header* begin = (ResChunk_header*)(nodeData + header.headerSize);
ResChunk_header* end = (ResChunk_header*)(nodeData + header.size);
int depth = 0;
while(begin < end)
{
switch(begin->type)
{
case RES_STRING_POOL_TYPE:
{
depth = 0;
stringPool.setTo((unsigned char*)begin);
}
break;
case RES_XML_RESOURCE_MAP_TYPE:
{
depth = 0;
resourceMap.setTo((unsigned char*)begin);
}
break;
case RES_XML_START_NAMESPACE_TYPE:
{
depth = 0;
ResXmlTreeNode* node = new ResXmlNamespace((unsigned char*)begin, NULL, depth);
elements.push_back(node);
topstack.push(node);
}
break;
case RES_XML_END_NAMESPACE_TYPE:
{
depth = 0;
topstack.pop();
ResXmlTreeNode* node = new ResXmlNamespace((unsigned char*)begin, NULL, depth);
elements.push_back(node);
}
break;
case RES_XML_START_ELEMENT_TYPE:
{
depth++;
ResXmlTreeNode* node = new ResXmlNamespace((unsigned char*)begin, topstack.top(), depth);
elements.push_back(node);
topstack.push(node);
}
break;
case RES_XML_END_ELEMENT_TYPE:
{
depth--;
topstack.pop();
ResXmlTreeNode* node = new ResXmlNamespace((unsigned char*)begin, topstack.top(), depth);
elements.push_back(node);
}
break;
default:
//unknown
break;
}
begin = (ResChunk_header*)((unsigned char*)begin + begin->size);
}
}
}
void serialize(unsigned char* nodeData, int& size)
{
int realsize = getSize();
if(size < realsize)
return;
size = realsize;
int offset = 0;
int left = 0;
memcpy(nodeData + offset, &header, sizeof(ResChunk_header));
offset += sizeof(ResChunk_header);
//写入字符串池
left = size - offset;
stringPool.serialize(nodeData + offset, left);
offset += stringPool.getSize();
//写入资源映射
left = size - offset;
resourceMap.serialize(nodeData + offset, left);
offset += resourceMap.getSize();
//写入XML树
for(int i=0;i<elements.size();i++)
{
left = size - offset;
elements->serialize(nodeData + offset, left);
offset += elements->getSize();
}
}
virtual int getSize()
{
int size = sizeof(ResChunk_header) + stringPool.getSize() + resourceMap.getSize();
for(int i=0;i<elements.size();i++)
{
size += elements->getSize();
}
return size;
}
void print()
{
wprintf(L"totalsize=%d\n",header.size);
stringPool.print();
resourceMap.print();
for(int i=0;i<elements.size();i++)
{
size += elements->print();
}
}
};
你这东西应该是能够直接修改一个已经编译了的AndroidManifest.xml的文件吧?
一开始看标题我还不明白是个啥。
确实是个不错的东西。建议再写一份C的。 可以可以!!
页:
[1]