|
MythTV
0.26-pre
|
00001 /* ParseBinary.cpp 00002 00003 Copyright (C) David C. J. Matthews 2004 dm at prolingua.co.uk 00004 00005 This program is free software; you can redistribute it and/or 00006 modify it under the terms of the GNU General Public License 00007 as published by the Free Software Foundation; either version 2 00008 of the License, or (at your option) any later version. 00009 00010 This program is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 GNU General Public License for more details. 00014 00015 You should have received a copy of the GNU General Public License 00016 along with this program; if not, write to the Free Software 00017 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00018 Or, point your browser to http://www.gnu.org/copyleft/gpl.html 00019 00020 */ 00021 00022 /* 00023 Parser for ASN1 binary notation. Does minimal syntax checking, assuming that this will already have 00024 been done before the binary was produced. Creates a MHParseNode tree structure. 00025 */ 00026 00027 #include "Engine.h" 00028 #include "ParseBinary.h" 00029 #include "ASN1Codes.h" 00030 #include "ParseNode.h" 00031 #include "BaseClasses.h" 00032 #include "Root.h" 00033 #include "Groups.h" 00034 #include "Logging.h" 00035 00036 MHParseBinary::MHParseBinary(QByteArray &program) 00037 { 00038 m_data = program; 00039 m_p = 0; 00040 } 00041 00042 #define INDEFINITE_LENGTH (-1) 00043 00044 // Get the next byte. In most all cases it's an error if we reach end-of-file 00045 // and we throw an exception. 00046 unsigned char MHParseBinary::GetNextChar() 00047 { 00048 if (m_p >= (int)m_data.size()) 00049 { 00050 MHERROR("Unexpected end of file"); 00051 } 00052 00053 return m_data[m_p++]; 00054 } 00055 00056 00057 // Parse a string argument. ASN1 strings can include nulls as valid characters. 00058 void MHParseBinary::ParseString(int endStr, MHOctetString &str) 00059 { 00060 // TODO: Don't deal with indefinite length at the moment. 00061 if (endStr == INDEFINITE_LENGTH) 00062 { 00063 MHERROR("Indefinite length strings are not implemented"); 00064 } 00065 00066 int nLength = endStr - m_p; 00067 unsigned char *stringValue = (unsigned char *)malloc(endStr - m_p); 00068 unsigned char *p = stringValue; 00069 00070 while (m_p < endStr) 00071 { 00072 *p++ = GetNextChar(); 00073 } 00074 00075 str.Copy(MHOctetString((const char *)stringValue, nLength)); 00076 free(stringValue); 00077 } 00078 00079 // Parse an integer argument. Also used for bool and enum. 00080 int MHParseBinary::ParseInt(int endInt) 00081 { 00082 int intVal = 0; 00083 bool firstByte = true; 00084 00085 if (endInt == INDEFINITE_LENGTH) 00086 { 00087 MHERROR("Indefinite length integers are not implemented"); 00088 } 00089 00090 while (m_p < endInt) 00091 { 00092 unsigned char ch = GetNextChar(); 00093 00094 // Integer values are signed so if the top bit is set in the first byte 00095 // we need to set the sign bit. 00096 if (firstByte && ch >= 128) 00097 { 00098 intVal = -1; 00099 } 00100 00101 firstByte = false; 00102 intVal = (intVal << 8) | ch; 00103 } 00104 00105 return intVal; 00106 } 00107 00108 00109 // Simple recursive parser for ASN1 BER. 00110 MHParseNode *MHParseBinary::DoParse() 00111 { 00112 unsigned char ch; 00113 // Tag class 00114 enum { Universal, Context/*, Pseudo*/ } tagClass = Universal; 00115 // Byte count of end of this item. Set to INDEFINITE_LENGTH if the length is Indefinite. 00116 int endOfItem; 00117 unsigned int tagNumber = 0; 00118 00119 // Read the first character. 00120 ch = GetNextChar(); 00121 00122 // ASN1 Coding rules: Top two bits (0 and 1) indicate the tag class. 00123 // 0x00 - Universal, 0x40 - Application, 0x80 - Context-specific, 0xC0 - Private 00124 // We only use Universal and Context. 00125 switch (ch & 0xC0) 00126 { 00127 case 0x00: // Universal 00128 tagClass = Universal; 00129 break; 00130 case 0x80: 00131 tagClass = Context; 00132 break; 00133 default: 00134 MHERROR(QString("Invalid tag class = %1").arg(ch, 0, 16)); 00135 } 00136 00137 // Bit 2 indicates whether it is a simple or compound type. Not used. 00138 // Lower bits are the tag number. 00139 tagNumber = ch & 0x1f; 00140 00141 if (tagNumber == 0x1f) // Except that if it is 0x1F then the tag is encoded in the following bytes. 00142 { 00143 tagNumber = 0; 00144 00145 do 00146 { 00147 ch = GetNextChar(); 00148 tagNumber = (tagNumber << 7) | (ch & 0x7f); 00149 } 00150 while (ch & 0x80); // Top bit set means there's more to come. 00151 } 00152 00153 // Next byte is the length. If it is less than 128 it is the actual length, otherwise it 00154 // gives the number of bytes containing the length, except that if this is zero the item 00155 // has an "indefinite" length and is terminated by two zero bytes. 00156 ch = GetNextChar(); 00157 00158 if (ch & 0x80) 00159 { 00160 int lengthOfLength = ch & 0x7f; 00161 00162 if (lengthOfLength == 0) 00163 { 00164 endOfItem = INDEFINITE_LENGTH; 00165 } 00166 else 00167 { 00168 endOfItem = 0; 00169 00170 while (lengthOfLength--) 00171 { 00172 ch = GetNextChar(); 00173 endOfItem = (endOfItem << 8) | ch; 00174 } 00175 00176 endOfItem += m_p; 00177 } 00178 } 00179 else 00180 { 00181 endOfItem = ch + m_p; 00182 } 00183 00184 if (tagClass == Context) 00185 { 00186 MHPTagged *pNode = new MHPTagged(tagNumber); 00187 00188 try 00189 { 00190 // The argument here depends on the particular tag we're processing. 00191 switch (tagNumber) 00192 { 00193 case C_MULTIPLE_SELECTION: 00194 case C_OBSCURED_INPUT: 00195 case C_INITIALLY_AVAILABLE: 00196 case C_WRAP_AROUND: 00197 case C_TEXT_WRAPPING: 00198 case C_INITIALLY_ACTIVE: 00199 case C_MOVING_CURSOR: 00200 case C_SHARED: 00201 case C_ENGINE_RESP: 00202 case C_TILING: 00203 case C_BORDERED_BOUNDING_BOX: 00204 { 00205 // BOOL 00206 // If there is no argument we need to indicate that so that it gets 00207 // the correct default value. 00208 if (m_p != endOfItem) 00209 { 00210 int intVal = ParseInt(endOfItem); // May raise an exception 00211 pNode->AddArg(new MHPBool(intVal != 0)); 00212 } 00213 00214 break; 00215 } 00216 00217 case C_INPUT_TYPE: 00218 case C_SLIDER_STYLE: 00219 case C_TERMINATION: 00220 case C_ORIENTATION: 00221 case C_HORIZONTAL_JUSTIFICATION: 00222 case C_BUTTON_STYLE: 00223 case C_START_CORNER: 00224 case C_LINE_ORIENTATION: 00225 case C_VERTICAL_JUSTIFICATION: 00226 case C_STORAGE: 00227 { 00228 // ENUM 00229 if (m_p != endOfItem) 00230 { 00231 int intVal = ParseInt(endOfItem); // May raise an exception 00232 pNode->AddArg(new MHPEnum(intVal)); 00233 } 00234 } 00235 00236 case C_INITIAL_PORTION: 00237 case C_STEP_SIZE: 00238 case C_INPUT_EVENT_REGISTER: 00239 case C_INITIAL_VALUE: 00240 case C_IP_CONTENT_HOOK: 00241 case C_MAX_VALUE: 00242 case C_MIN_VALUE: 00243 case C_LINE_ART_CONTENT_HOOK: 00244 case C_BITMAP_CONTENT_HOOK: 00245 case C_TEXT_CONTENT_HOOK: 00246 case C_STREAM_CONTENT_HOOK: 00247 case C_MAX_LENGTH: 00248 case C_CHARACTER_SET: 00249 case C_ORIGINAL_TRANSPARENCY: 00250 case C_ORIGINAL_GC_PRIORITY: 00251 case C_LOOPING: 00252 case C_ORIGINAL_LINE_STYLE: 00253 case C_STANDARD_VERSION: 00254 case C_ORIGINAL_LINE_WIDTH: 00255 case C_CONTENT_HOOK: 00256 case C_CONTENT_CACHE_PRIORITY: 00257 case C_COMPONENT_TAG: 00258 case C_ORIGINAL_VOLUME: 00259 case C_PROGRAM_CONNECTION_TAG: 00260 case C_CONTENT_SIZE: 00261 { 00262 // INT 00263 if (m_p != endOfItem) 00264 { 00265 int intVal = ParseInt(endOfItem); // May raise an exception 00266 pNode->AddArg(new MHPInt(intVal)); 00267 } 00268 } 00269 00270 case C_OBJECT_INFORMATION: 00271 case C_CONTENT_REFERENCE: 00272 case C_FONT_ATTRIBUTES: 00273 case C_CHAR_LIST: 00274 case C_NAME: 00275 case C_ORIGINAL_LABEL: 00276 { 00277 // STRING 00278 // Unlike INT, BOOL and ENUM we can't distinguish an empty string 00279 // from a missing string. 00280 MHOctetString str; 00281 ParseString(endOfItem, str); 00282 pNode->AddArg(new MHPString(str)); 00283 } 00284 00285 default: 00286 { 00287 // Everything else has either no argument or is self-describing 00288 // TODO: Handle indefinite length. 00289 if (endOfItem == INDEFINITE_LENGTH) 00290 { 00291 MHERROR("Indefinite length arguments are not implemented"); 00292 } 00293 00294 while (m_p < endOfItem) 00295 { 00296 pNode->AddArg(DoParse()); 00297 } 00298 } 00299 } 00300 } 00301 catch (...) 00302 { 00303 // Memory clean-up 00304 delete pNode; 00305 throw; 00306 } 00307 00308 return pNode; 00309 } 00310 else // Universal - i.e. a primitive type. 00311 { 00312 // Tag values 00313 00314 switch (tagNumber) 00315 { 00316 case U_BOOL: // Boolean 00317 { 00318 int intVal = ParseInt(endOfItem); 00319 return new MHPBool(intVal != 0); 00320 } 00321 case U_INT: // Integer 00322 { 00323 int intVal = ParseInt(endOfItem); 00324 return new MHPInt(intVal); 00325 } 00326 case U_ENUM: // ENUM 00327 { 00328 int intVal = ParseInt(endOfItem); 00329 return new MHPEnum(intVal); 00330 } 00331 case U_STRING: // String 00332 { 00333 MHOctetString str; 00334 ParseString(endOfItem, str); 00335 return new MHPString(str); 00336 } 00337 case U_NULL: // ASN1 NULL 00338 { 00339 return new MHPNull; 00340 } 00341 case U_SEQUENCE: // Sequence 00342 { 00343 MHParseSequence *pNode = new MHParseSequence(); 00344 00345 if (endOfItem == INDEFINITE_LENGTH) 00346 { 00347 MHERROR("Indefinite length sequences are not implemented"); 00348 } 00349 00350 try 00351 { 00352 while (m_p < endOfItem) 00353 { 00354 pNode->Append(DoParse()); 00355 } 00356 } 00357 catch (...) 00358 { 00359 // Memory clean-up if error. 00360 delete pNode; 00361 throw; 00362 } 00363 00364 return pNode; 00365 } 00366 default: 00367 MHERROR(QString("Unknown universal %1").arg(tagNumber)); 00368 } 00369 } 00370 }
1.7.6.1