| | 110 | /** Endian-neutral conversion of four bytes into one uint32 |
| | 111 | * |
| | 112 | * @param d [in] pointer to byte array |
| | 113 | * |
| | 114 | * @retval uint32 assembled from four bytes |
| | 115 | */ |
| | 116 | uint32_t PkgReadU32(uint8_t *d) |
| | 117 | { |
| | 118 | return ((d[0]<<24)|(d[1]<<16)|(d[2]<<8)|(d[3])); |
| | 119 | } |
| | 120 | |
| | 121 | /*------------------------------------------------------------------------*/ |
| | 122 | /** Generate a ref from package data |
| | 123 | * |
| | 124 | * @param pkg [inout] the package |
| | 125 | * @param p_obj [in] offset to Ref data relative to package start |
| | 126 | * |
| | 127 | * @retval Newt object version of package Ref |
| | 128 | */ |
| | 129 | newtRef PkgReadRef(pkg_stream_t *pkg, uint32_t p_obj) |
| | 130 | { |
| | 131 | uint32_t ref = PkgReadU32(pkg->data + p_obj); |
| | 132 | newtRef result = kNewtRefNIL; |
| | 133 | |
| | 134 | switch (ref&3) { |
| | 135 | case 0: // integer |
| | 136 | result = NSINT(ref>>2); |
| | 137 | break; |
| | 138 | case 1: // pointer |
| | 139 | result = PkgReadObject(pkg, ref&~3); |
| | 140 | break; |
| | 141 | case 2: // special |
| | 142 | if (ref==kNewtRefTRUE) result = kNewtRefTRUE; |
| | 143 | else if (ref==kNewtRefNIL) result = kNewtRefNIL; |
| | 144 | else if (ref&0x0f==0x0a) result = NewtMakeCharacter(ref>>4); |
| | 145 | else if (ref==kNewtSymbolClass) result = kNewtSymbolClass; |
| | 146 | else if (ref==0x32) { |
| | 147 | result = 0x32; |
| | 148 | printf("*** PkgReader: PkgReadRef - unsupported ref 0x%08x - what is this?\n", ref); |
| | 149 | } else { |
| | 150 | # ifdef DEBUG_PKG |
| | 151 | printf("*** PkgReader: PkgReadRef - unsupported ref 0x%08x\n", ref); |
| | 152 | # endif |
| | 153 | result = ref; |
| | 154 | } |
| | 155 | break; |
| | 156 | case 3: // magic pointer |
| | 157 | # ifdef __NAMED_MAGIC_POINTER__ |
| | 158 | result = kNewtRefNIL; // no timplemented |
| | 159 | # else |
| | 160 | result = ref; // already a correct magic pointer |
| | 161 | # endif |
| | 162 | break; |
| | 163 | } |
| | 164 | |
| | 165 | return result; |
| | 166 | } |
| | 167 | |
| | 168 | /*------------------------------------------------------------------------*/ |
| | 169 | /** Generate a binary object from package data |
| | 170 | * |
| | 171 | * @param pkg [inout] the package |
| | 172 | * @param p_obj [in] offset to binary data object relative to package start |
| | 173 | * |
| | 174 | * @retval Newt object version of binary object |
| | 175 | */ |
| | 176 | newtRef PkgReadBinaryObject(pkg_stream_t *pkg, uint32_t p_obj) |
| | 177 | { |
| | 178 | uint32_t size = PkgReadU32(pkg->data + p_obj) >> 8; |
| | 179 | newtRef klass, result = kNewtRefNIL; |
| | 180 | newtRef ins = NSSYM0(instructions); |
| | 181 | |
| | 182 | klass = PkgReadRef(pkg, p_obj+8); |
| | 183 | |
| | 184 | if (klass==kNewtSymbolClass) { |
| | 185 | result = NewtMakeSymbol(pkg->data + p_obj + 16); |
| | 186 | } else if (klass==NSSYM0(string)) { |
| | 187 | char *src = pkg->data + p_obj + 12; |
| | 188 | int sze = size-12; |
| | 189 | # ifdef HAVE_LIBICONV |
| | 190 | size_t buflen; |
| | 191 | char *buf = NewtIconv(pkg->from_utf16, src, sze, &buflen); |
| | 192 | if (buf) { |
| | 193 | result = NewtMakeString2(buf, buflen, false); |
| | 194 | } |
| | 195 | # endif /* HAVE_LIBICONV */ |
| | 196 | if (result==kNewtRefNIL) |
| | 197 | result = NewtMakeString2(src, sze, false); |
| | 198 | } else if (klass==NSSYM0(int32)) { |
| | 199 | uint32_t v = PkgReadU32(pkg->data + p_obj + 12); |
| | 200 | result = NewtMakeInt32(v); |
| | 201 | } else if (klass==NSSYM0(real)) { |
| | 202 | double *v = (double*)(pkg->data + p_obj + 12); |
| | 203 | result = NewtMakeReal(ntohd(*v)); |
| | 204 | } else if (klass==NSSYM0(instructions)) { |
| | 205 | result = NewtMakeBinary(klass, pkg->data + p_obj + 12, size-12, false); |
| | 206 | # ifdef DEBUG_PKG_DIS |
| | 207 | printf("*** PkgReader: PkgReadBinaryObject - dumping byte code\n"); |
| | 208 | NVMDumpBC(stdout, result); |
| | 209 | # endif |
| | 210 | } else { |
| | 211 | // bits: the bits in the icon |
| | 212 | // mask: the transparency mask for the icon |
| | 213 | # ifdef DEBUG_PKG |
| | 214 | if (klass) { |
| | 215 | printf("*** PkgReader: PkgReadBinaryObject - unknown class "); |
| | 216 | NewtPrintObject(stdout, klass); |
| | 217 | } |
| | 218 | # endif |
| | 219 | result = NewtMakeBinary(klass, pkg->data + p_obj + 12, size-12, false); |
| | 220 | } |
| | 221 | |
| | 222 | return result; |
| | 223 | } |
| | 224 | |
| | 225 | /*------------------------------------------------------------------------*/ |
| | 226 | /** Generate an array from package data |
| | 227 | * |
| | 228 | * @param pkg [inout] the package |
| | 229 | * @param p_obj [in] offset to array data relative to package start |
| | 230 | * |
| | 231 | * @retval Newt object version of package Array |
| | 232 | */ |
| | 233 | newtRef PkgReadArrayObject(pkg_stream_t *pkg, uint32_t p_obj) |
| | 234 | { |
| | 235 | uint32_t size = PkgReadU32(pkg->data + p_obj) >> 8; |
| | 236 | uint32_t num_slots = size/4 - 3; |
| | 237 | uint32_t i; |
| | 238 | newtRef array, klass; |
| | 239 | |
| | 240 | klass = PkgReadRef(pkg, p_obj+8); |
| | 241 | array = NewtMakeArray(klass, num_slots); |
| | 242 | |
| | 243 | if (NewtRefIsNotNIL(array)) { |
| | 244 | for (i=0; i<num_slots; i++) { |
| | 245 | NewtSetArraySlot(array, i, PkgReadRef(pkg, p_obj+12 + 4*i)); |
| | 246 | } |
| | 247 | } |
| | 248 | |
| | 249 | return array; |
| | 250 | } |
| | 251 | |
| | 252 | |
| | 253 | /*------------------------------------------------------------------------*/ |
| | 254 | /** Generate a frame from package data |
| | 255 | * |
| | 256 | * @param pkg [inout] the package |
| | 257 | * @param p_obj [in] offset to frame data relative to package start |
| | 258 | * |
| | 259 | * @retval Newt object version of package Frame |
| | 260 | */ |
| | 261 | newtRef PkgReadFrameObject(pkg_stream_t *pkg, uint32_t p_obj) |
| | 262 | { |
| | 263 | uint32_t size = PkgReadU32(pkg->data + p_obj) >> 8; |
| | 264 | uint32_t i, num_slots = size/4 - 3; |
| | 265 | newtRef frame = kNewtRefNIL, map; |
| | 266 | |
| | 267 | map = PkgReadRef(pkg, p_obj+8); |
| | 268 | |
| | 269 | frame = NewtMakeFrame(map, num_slots); |
| | 270 | |
| | 271 | if (NewtRefIsNotNIL(frame)) { |
| | 272 | |
| | 273 | newtRef *slot = NewtRefToSlots(frame); |
| | 274 | for (i=0; i<num_slots; i++) { |
| | 275 | slot[i] = PkgReadRef(pkg, p_obj+12 + 4*i); |
| | 276 | } |
| | 277 | } |
| | 278 | |
| | 279 | return frame; |
| | 280 | } |
| | 281 | |
| | 282 | /*------------------------------------------------------------------------*/ |
| | 283 | /** Recursively read the object at the given offset |
| | 284 | * |
| | 285 | * @param pkg [inout] the package |
| | 286 | * @param p_obj [in] offset to object relative to package start |
| | 287 | * |
| | 288 | * @retval Newt object version of package object |
| | 289 | */ |
| | 290 | newtRef PkgReadObject(pkg_stream_t *pkg, uint32_t p_obj) |
| | 291 | { |
| | 292 | uint32_t obj = PkgReadU32(pkg->data + p_obj); |
| | 293 | newtRef ret = kNewtRefNIL; |
| | 294 | |
| | 295 | switch (obj & 0xff) { |
| | 296 | case 0x40: // binary object |
| | 297 | ret = PkgReadBinaryObject(pkg, p_obj); |
| | 298 | break; |
| | 299 | case 0x40 | kObjSlotted: // array |
| | 300 | ret = PkgReadArrayObject(pkg, p_obj); |
| | 301 | break; |
| | 302 | case 0x40 | kObjSlotted | kObjFrame: // frame |
| | 303 | ret = PkgReadFrameObject(pkg, p_obj); |
| | 304 | break; |
| | 305 | case 0x40 | kObjFrame: // not defined |
| | 306 | default: |
| | 307 | # ifdef DEBUG_PKG |
| | 308 | printf("*** PkgReader: PkgReadObject - unsupported object 0x%08x\n", obj); |
| | 309 | # endif |
| | 310 | break; |
| | 311 | } |
| | 312 | return ret; |
| | 313 | } |
| | 314 | |
| | 315 | /*------------------------------------------------------------------------*/ |
| | 316 | /** Read a NOS part from the package file. |
| | 317 | * |
| | 318 | * @param pkg [inout] the package |
| | 319 | * |
| | 320 | * @retval Newt object with contents of NOS part |
| | 321 | */ |
| | 322 | newtRef PkgReadNOSPart(pkg_stream_t *pkg) |
| | 323 | { |
| | 324 | uint32_t p_obj = PkgReadU32(pkg->part+12); |
| | 325 | return PkgReadObject(pkg, p_obj&~3); |
| | 326 | } |
| | 327 | |
| | 328 | /*------------------------------------------------------------------------*/ |
| 94 | | newtRefVar r = kNewtRefNIL; |
| 95 | | // FIXME prepare pkg with offsets and pointer for reading this Part |
| 96 | | // FIXME store 8/4 byte alignment flag (no so important for reading though) |
| 97 | | // FIXME call PkgReadPart2 to recursively scan all Refs in the part |
| 98 | | return r; |
| | 338 | uint32_t flags; |
| | 339 | newtRefVar frame; |
| | 340 | newtRefVar ptv[] = { |
| | 341 | NS_CLASS, NSSYM(PackagePart), |
| | 342 | NSSYM(info), kNewtRefNIL, |
| | 343 | NSSYM(flags), kNewtRefNIL, |
| | 344 | NSSYM(type), kNewtRefNIL, |
| | 345 | NSSYM(data), kNewtRefNIL |
| | 346 | }; |
| | 347 | |
| | 348 | pkg->part_header = pkg->part_headers + index; |
| | 349 | pkg->part = pkg->data |
| | 350 | + ntohl(pkg->header->directorySize) |
| | 351 | + ntohl(pkg->part_header->offset); |
| | 352 | flags = ntohl(pkg->part_header->flags); |
| | 353 | |
| | 354 | frame = NewtMakeFrame2(sizeof(ptv) / (sizeof(newtRefVar) * 2), ptv); |
| | 355 | |
| | 356 | NcSetSlot(frame, NSSYM(flags), NewtMakeInt32(flags)); |
| | 357 | NcSetSlot(frame, NSSYM(type), NewtMakeBinary(kNewtRefUnbind, |
| | 358 | (uint8_t*)&pkg->part_header->type, 4, true)); |
| | 359 | |
| | 360 | switch (flags&0x03) { |
| | 361 | case kNOSPart: |
| | 362 | if ( PkgReadU32(pkg->part) !=0x00001041 |
| | 363 | || PkgReadU32(pkg->part+8)!=0x00000002) |
| | 364 | { |
| | 365 | # ifdef DEBUG_PKG |
| | 366 | printf("*** PkgReader: PkgReadPart - unsupported NOS Part intro at %d\n", |
| | 367 | pkg->part-pkg->data); |
| | 368 | # endif |
| | 369 | break; |
| | 370 | } |
| | 371 | NcSetSlot(frame, NSSYM(info), PkgReadVardataBinary(pkg, &pkg->part_header->info)); |
| | 372 | NcSetSlot(frame, NSSYM(data), PkgReadNOSPart(pkg)); |
| | 373 | break; |
| | 374 | case kProtocolPart: |
| | 375 | case kRawPart: |
| | 376 | default: |
| | 377 | # ifdef DEBUG_PKG |
| | 378 | printf("*** PkgReader: PkgReadPart - unsupported part 0x%08x\n", flags); |
| | 379 | # endif |
| | 380 | break; |
| | 381 | } |
| | 382 | return frame; |
| | 383 | } |
| | 384 | |
| | 385 | /*------------------------------------------------------------------------*/ |
| | 386 | /** Read binary data from the Variable Data area |
| | 387 | * |
| | 388 | * @param pkg [inout] the package |
| | 389 | * @param info_ref [in] pointer to the reference |
| | 390 | * |
| | 391 | * @retval Binary object |
| | 392 | */ |
| | 393 | newtRef PkgReadVardataBinary(pkg_stream_t *pkg, pkg_info_ref_t *info_ref) |
| | 394 | { |
| | 395 | if (info_ref->size==0) { |
| | 396 | return kNewtRefNIL; |
| | 397 | } else { |
| | 398 | uint8_t *src = pkg->var_len_data + ntohs(info_ref->offset); |
| | 399 | int size = ntohs(info_ref->size); |
| | 400 | return NewtMakeBinary(kNewtRefUnbind, src, size, true); |
| | 401 | } |
| | 402 | } |
| | 403 | |
| | 404 | /*------------------------------------------------------------------------*/ |
| | 405 | /** Read a UTF16 string from the Variable Data area |
| | 406 | * |
| | 407 | * @param pkg [inout] the package |
| | 408 | * @param info_ref [in] pointer to the reference |
| | 409 | * |
| | 410 | * @retval String object |
| | 411 | */ |
| | 412 | newtRef PkgReadVardataString(pkg_stream_t *pkg, pkg_info_ref_t *info_ref) |
| | 413 | { |
| | 414 | if (info_ref->size==0) { |
| | 415 | return kNewtRefNIL; |
| | 416 | } else { |
| | 417 | char *src = pkg->var_len_data + ntohs(info_ref->offset); |
| | 418 | int size = ntohs(info_ref->size); |
| | 419 | # ifdef HAVE_LIBICONV |
| | 420 | size_t buflen; |
| | 421 | char *buf = NewtIconv(pkg->from_utf16, src, size, &buflen); |
| | 422 | if (buf) { |
| | 423 | return NewtMakeString2(buf, buflen, false); |
| | 424 | } |
| | 425 | # endif /* HAVE_LIBICONV */ |
| | 426 | return NewtMakeString2(src, size, false); |
| | 427 | } |
| | 428 | } |
| | 429 | |
| | 430 | /*------------------------------------------------------------------------*/ |
| | 431 | /** Read the package header and create a Frame object describing it. |
| | 432 | * |
| | 433 | * @param pkg [inout] the package |
| | 434 | * |
| | 435 | * @retval Frame describing the package |
| | 436 | */ |
| | 437 | newtRef PkgReadHeader(pkg_stream_t *pkg) |
| | 438 | { |
| | 439 | newtRefVar fnv[] = { |
| | 440 | NS_CLASS, NSSYM(PackageHeader), |
| | 441 | NSSYM(version), kNewtRefNIL, |
| | 442 | NSSYM(copyright), kNewtRefNIL, |
| | 443 | NSSYM(name), kNewtRefNIL, |
| | 444 | NSSYM(flags), kNewtRefNIL, |
| | 445 | NSSYM(parts), kNewtRefNIL |
| | 446 | }; |
| | 447 | newtRefVar frame = NewtMakeFrame2(sizeof(fnv) / (sizeof(newtRefVar) * 2), fnv); |
| | 448 | newtRefVar parts; |
| | 449 | |
| | 450 | NcSetSlot(frame, NSSYM(version), NSINT(pkg->verno)); |
| | 451 | NcSetSlot(frame, NSSYM(copyright), PkgReadVardataString(pkg, &pkg->header->copyright)); |
| | 452 | NcSetSlot(frame, NSSYM(name), PkgReadVardataString(pkg, &pkg->header->name)); |
| | 453 | NcSetSlot(frame, NSSYM(flags), NewtMakeInt32(ntohl(pkg->header->flags))); |
| | 454 | // all other header values can be derived form the archive itself |
| | 455 | // or can be calculated at creation time |
| | 456 | |
| | 457 | parts = NewtMakeArray(kNewtRefNIL, pkg->num_parts); |
| | 458 | |
| | 459 | if (NewtRefIsNotNIL(parts)) |
| | 460 | { |
| | 461 | int32_t i, n = pkg->num_parts; |
| | 462 | |
| | 463 | NcSetSlot(frame, NSSYM(parts), parts); |
| | 464 | for (i = 0; i < n; i++) |
| | 465 | { |
| | 466 | NewtSetArraySlot(parts, i, PkgReadPart(pkg, i)); |
| | 467 | if (pkg->lastErr != kNErrNone) break; |
| | 468 | } |
| | 469 | } |
| | 470 | |
| | 471 | return frame; |